/*++

Module Name:

    kchecksum.cpp

Abstract:

    This file contains the user mode and kernel mode implementations for checksum computations object.  This code comes from
    the MSN project.  The contibutors to the implementation are mentioned in comments in the code.

Author:

Environment:

    Kernel mode and User mode

Notes:

Revision History:

--*/

#include <ktl.h>
#if !defined(PLATFORM_UNIX)
#include <intrin.h>
#else
inline uint64_t RotateRight64(uint64_t Value, int Shift)
{
    return (Value >> Shift) | (Value << (64 - Shift));
}
#endif



#define CSCRCAPI

typedef UCHAR UInt8;
typedef ULONG UInt32;
typedef ULONGLONG UInt64;
typedef ULONG_PTR Size_t;

#if KTL_USER_MODE
#else
typedef LONG BOOL;
#endif

LONG KChecksum::DisableHwCrcAssist = FALSE;

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */


//
// Few words of explanation: template implementation of CRC was moved to CsCrc.cpp for a reason,
// and this reason is called "performance". When compiling CsCrc.cpp, the code will be optimized
// for time instead of size (which is default build setting).
//



/* -------------------------------------- 32-bit CRC -------------------------------------- */
/*                                        ----------                                        */

//
// Generating polynomial for CRC32 = CRC<UInt32> is
// 0x82f63b78 =
//              x^32 + x^28 + x^27 + x^26 + x^25 + x^23 + x^22 + x^20 + x^19 + x^18 + x^14 +
//                   + x^13 + x^11 + x^10 + x^9  + x^8  + x^6  + x^0
//

//
// Compute CRC32 of uSize bytes starting at pSrc with initial CRC value of uCrc
// It guarantees that CrcCompute (pSrc, uSize0, uValue) =
// = CrcCompute (pSrc + uOffset, uSize - uOffset, Compute (pSrc, uOffset, uValue)),
// i.e. CRC can be computed incrementally
//

UInt32
CSCRCAPI
CsCrc32Compute (
    const void *pSrc,
    Size_t      uSize,
    UInt32      uCrc
);

//
// Compute CRC of concatenation of two blocks with known CRCs without touching actual data (and it's fast).
// I.e. if
//      uCrcA = CrcCompute (pSrc, uSizeA, uStartingCrcA) and
//      uCrcB = CRC (pSrc + uSizeA, uSizeB, uStartingCrcB),
// then
//      CrcCompute (pSrc, uSizeA + uSizeB, uStartingCrcAB) = CrcConcatenate (
//          uStartingCrcAB,
//          uStartingCrcA, uCrcA, uSizeA,
//          uStartingCrcB, uCrcB, uSizeB
//      );
//
//
UInt32
CSCRCAPI
CsCrc32Concatenate (
    UInt32 uInitialCrcAB,
    UInt32 uInitialCrcA,
    UInt32 uFinalCrcA,
    UInt64 uSizeA,
    UInt32 uInitialCrcB,
    UInt32 uFinalCrcB,
    UInt64 uSizeB
);


//
// Return TRUE if CRC32 computations are working correctly
//
BOOL
CSCRCAPI
CsCrc32SelfTest (
    void
);


/* -------------------------------------- 64-bit CRC -------------------------------------- */
/*                                        ----------                                        */


//
// Generating polynomial for CRC64 = CRC<UInt64> is
// 0x9a6c9329ac4bc9b5 =
//                      x^64 + x^63 + x^61 + x^59 + x^58 + x^56 + x^55 + x^52 + x^49 + x^48 + x^47 +
//                           + x^46 + x^44 + x^41 + x^37 + x^36 + x^34 + x^32 + x^31 + x^28 + x^26 +
//                           + x^23 + x^22 + x^19 + x^16 + x^13 + x^12 + x^10 + x^9  + x^6  + x^4  +
//                           + x^3  + x^0
//

//
// Compute CRC64 of uSize bytes starting at pSrc with initial CRC value of uCrc
// It guarantees that CrcCompute (pSrc, uSize0, uValue) =
// = CrcCompute (pSrc + uOffset, uSize - uOffset, Compute (pSrc, uOffset, uValue)),
// i.e. CRC can be computed incrementally
//

UInt64
CSCRCAPI
CsCrc64Compute (
    const void *pSrc,
    Size_t      uSize,
    UInt64      uCrc
);

//
// Compute CRC of concatenation of two blocks with known CRCs without touching actual data (and it's fast).
// I.e. if
//      uCrcA = CrcCompute (pSrc, uSizeA, uStartingCrcA) and
//      uCrcB = CRC (pSrc + uSizeA, uSizeB, uStartingCrcB),
// then
//      CrcCompute (pSrc, uSizeA + uSizeB, uStartingCrcAB) = CrcConcatenate (
//          uStartingCrcAB,
//          uStartingCrcA, uCrcA, uSizeA,
//          uStartingCrcB, uCrcB, uSizeB
//      );
//
//
UInt64
CSCRCAPI
CsCrc64Concatenate (
    UInt64 uInitialCrcAB,
    UInt64 uInitialCrcA,
    UInt64 uFinalCrcA,
    UInt64 uSizeA,
    UInt64 uInitialCrcB,
    UInt64 uFinalCrcB,
    UInt64 uSizeB
);

//
// Return TRUE if CRC64 computations are working correctly
//
BOOL
CSCRCAPI
CsCrc64SelfTest (
    void
);


#ifdef __cplusplus
}; // extern "C"
#endif /* __cplusplus */

/* ---------------------------------- Tables for Crc32 ----------------------------------- */
/*                                    ----------------                                     */

//
// Generating polynomial for Crc32 is
// 0x0000000082f63b78 =
//                      x^64 + x^60 + x^59 + x^58 + x^57 + x^55 + x^54 + x^52 + x^51 + x^50 + x^46 +
//                           + x^45 + x^43 + x^42 + x^41 + x^40 + x^38 + x^32
//

UInt64
CsCrc32Mult[64] =
{
   0x0000000000800000, 0x0000000000008000, 0x0000000082f63b78, 0x000000006ea2d55c,
   0x0000000018b8ea18, 0x00000000510ac59a, 0x00000000b82be955, 0x00000000b8fdb1e7,
   0x0000000088e56f72, 0x0000000074c360a4, 0x00000000e4172b16, 0x000000000d65762a,
   0x0000000035d73a62, 0x0000000028461564, 0x00000000bf455269, 0x00000000e2ea32dc,
   0x00000000fe7740e6, 0x00000000f946610b, 0x000000003c204f8f, 0x00000000538586e3,
   0x0000000059726915, 0x00000000734d5309, 0x00000000bc1ac763, 0x000000007d0722cc,
   0x00000000d289cabe, 0x00000000e94ca9bc, 0x0000000005b74f3f, 0x00000000a51e1f42,
   0x0000000040000000, 0x0000000020000000, 0x0000000008000000, 0x0000000000800000,
   0x0000000000008000, 0x0000000082f63b78, 0x000000006ea2d55c, 0x0000000018b8ea18,
   0x00000000510ac59a, 0x00000000b82be955, 0x00000000b8fdb1e7, 0x0000000088e56f72,
   0x0000000074c360a4, 0x00000000e4172b16, 0x000000000d65762a, 0x0000000035d73a62,
   0x0000000028461564, 0x00000000bf455269, 0x00000000e2ea32dc, 0x00000000fe7740e6,
   0x00000000f946610b, 0x000000003c204f8f, 0x00000000538586e3, 0x0000000059726915,
   0x00000000734d5309, 0x00000000bc1ac763, 0x000000007d0722cc, 0x00000000d289cabe,
   0x00000000e94ca9bc, 0x0000000005b74f3f, 0x00000000a51e1f42, 0x0000000040000000,
   0x0000000020000000, 0x0000000008000000, 0x0000000000800000, 0x0000000000008000,
  };

static UInt64 CsCrc32Map1[256] =
{
   0x0000000000000000, 0x00000000f26b8303, 0x00000000e13b70f7, 0x000000001350f3f4,
   0x00000000c79a971f, 0x0000000035f1141c, 0x0000000026a1e7e8, 0x00000000d4ca64eb,
   0x000000008ad958cf, 0x0000000078b2dbcc, 0x000000006be22838, 0x000000009989ab3b,
   0x000000004d43cfd0, 0x00000000bf284cd3, 0x00000000ac78bf27, 0x000000005e133c24,
   0x00000000105ec76f, 0x00000000e235446c, 0x00000000f165b798, 0x00000000030e349b,
   0x00000000d7c45070, 0x0000000025afd373, 0x0000000036ff2087, 0x00000000c494a384,
   0x000000009a879fa0, 0x0000000068ec1ca3, 0x000000007bbcef57, 0x0000000089d76c54,
   0x000000005d1d08bf, 0x00000000af768bbc, 0x00000000bc267848, 0x000000004e4dfb4b,
   0x0000000020bd8ede, 0x00000000d2d60ddd, 0x00000000c186fe29, 0x0000000033ed7d2a,
   0x00000000e72719c1, 0x00000000154c9ac2, 0x00000000061c6936, 0x00000000f477ea35,
   0x00000000aa64d611, 0x00000000580f5512, 0x000000004b5fa6e6, 0x00000000b93425e5,
   0x000000006dfe410e, 0x000000009f95c20d, 0x000000008cc531f9, 0x000000007eaeb2fa,
   0x0000000030e349b1, 0x00000000c288cab2, 0x00000000d1d83946, 0x0000000023b3ba45,
   0x00000000f779deae, 0x0000000005125dad, 0x000000001642ae59, 0x00000000e4292d5a,
   0x00000000ba3a117e, 0x000000004851927d, 0x000000005b016189, 0x00000000a96ae28a,
   0x000000007da08661, 0x000000008fcb0562, 0x000000009c9bf696, 0x000000006ef07595,
   0x00000000417b1dbc, 0x00000000b3109ebf, 0x00000000a0406d4b, 0x00000000522bee48,
   0x0000000086e18aa3, 0x00000000748a09a0, 0x0000000067dafa54, 0x0000000095b17957,
   0x00000000cba24573, 0x0000000039c9c670, 0x000000002a993584, 0x00000000d8f2b687,
   0x000000000c38d26c, 0x00000000fe53516f, 0x00000000ed03a29b, 0x000000001f682198,
   0x000000005125dad3, 0x00000000a34e59d0, 0x00000000b01eaa24, 0x0000000042752927,
   0x0000000096bf4dcc, 0x0000000064d4cecf, 0x0000000077843d3b, 0x0000000085efbe38,
   0x00000000dbfc821c, 0x000000002997011f, 0x000000003ac7f2eb, 0x00000000c8ac71e8,
   0x000000001c661503, 0x00000000ee0d9600, 0x00000000fd5d65f4, 0x000000000f36e6f7,
   0x0000000061c69362, 0x0000000093ad1061, 0x0000000080fde395, 0x0000000072966096,
   0x00000000a65c047d, 0x000000005437877e, 0x000000004767748a, 0x00000000b50cf789,
   0x00000000eb1fcbad, 0x00000000197448ae, 0x000000000a24bb5a, 0x00000000f84f3859,
   0x000000002c855cb2, 0x00000000deeedfb1, 0x00000000cdbe2c45, 0x000000003fd5af46,
   0x000000007198540d, 0x0000000083f3d70e, 0x0000000090a324fa, 0x0000000062c8a7f9,
   0x00000000b602c312, 0x0000000044694011, 0x000000005739b3e5, 0x00000000a55230e6,
   0x00000000fb410cc2, 0x00000000092a8fc1, 0x000000001a7a7c35, 0x00000000e811ff36,
   0x000000003cdb9bdd, 0x00000000ceb018de, 0x00000000dde0eb2a, 0x000000002f8b6829,
   0x0000000082f63b78, 0x00000000709db87b, 0x0000000063cd4b8f, 0x0000000091a6c88c,
   0x00000000456cac67, 0x00000000b7072f64, 0x00000000a457dc90, 0x00000000563c5f93,
   0x00000000082f63b7, 0x00000000fa44e0b4, 0x00000000e9141340, 0x000000001b7f9043,
   0x00000000cfb5f4a8, 0x000000003dde77ab, 0x000000002e8e845f, 0x00000000dce5075c,
   0x0000000092a8fc17, 0x0000000060c37f14, 0x0000000073938ce0, 0x0000000081f80fe3,
   0x0000000055326b08, 0x00000000a759e80b, 0x00000000b4091bff, 0x00000000466298fc,
   0x000000001871a4d8, 0x00000000ea1a27db, 0x00000000f94ad42f, 0x000000000b21572c,
   0x00000000dfeb33c7, 0x000000002d80b0c4, 0x000000003ed04330, 0x00000000ccbbc033,
   0x00000000a24bb5a6, 0x00000000502036a5, 0x000000004370c551, 0x00000000b11b4652,
   0x0000000065d122b9, 0x0000000097baa1ba, 0x0000000084ea524e, 0x000000007681d14d,
   0x000000002892ed69, 0x00000000daf96e6a, 0x00000000c9a99d9e, 0x000000003bc21e9d,
   0x00000000ef087a76, 0x000000001d63f975, 0x000000000e330a81, 0x00000000fc588982,
   0x00000000b21572c9, 0x00000000407ef1ca, 0x00000000532e023e, 0x00000000a145813d,
   0x00000000758fe5d6, 0x0000000087e466d5, 0x0000000094b49521, 0x0000000066df1622,
   0x0000000038cc2a06, 0x00000000caa7a905, 0x00000000d9f75af1, 0x000000002b9cd9f2,
   0x00000000ff56bd19, 0x000000000d3d3e1a, 0x000000001e6dcdee, 0x00000000ec064eed,
   0x00000000c38d26c4, 0x0000000031e6a5c7, 0x0000000022b65633, 0x00000000d0ddd530,
   0x000000000417b1db, 0x00000000f67c32d8, 0x00000000e52cc12c, 0x000000001747422f,
   0x0000000049547e0b, 0x00000000bb3ffd08, 0x00000000a86f0efc, 0x000000005a048dff,
   0x000000008ecee914, 0x000000007ca56a17, 0x000000006ff599e3, 0x000000009d9e1ae0,
   0x00000000d3d3e1ab, 0x0000000021b862a8, 0x0000000032e8915c, 0x00000000c083125f,
   0x00000000144976b4, 0x00000000e622f5b7, 0x00000000f5720643, 0x0000000007198540,
   0x00000000590ab964, 0x00000000ab613a67, 0x00000000b831c993, 0x000000004a5a4a90,
   0x000000009e902e7b, 0x000000006cfbad78, 0x000000007fab5e8c, 0x000000008dc0dd8f,
   0x00000000e330a81a, 0x00000000115b2b19, 0x00000000020bd8ed, 0x00000000f0605bee,
   0x0000000024aa3f05, 0x00000000d6c1bc06, 0x00000000c5914ff2, 0x0000000037faccf1,
   0x0000000069e9f0d5, 0x000000009b8273d6, 0x0000000088d28022, 0x000000007ab90321,
   0x00000000ae7367ca, 0x000000005c18e4c9, 0x000000004f48173d, 0x00000000bd23943e,
   0x00000000f36e6f75, 0x000000000105ec76, 0x0000000012551f82, 0x00000000e03e9c81,
   0x0000000034f4f86a, 0x00000000c69f7b69, 0x00000000d5cf889d, 0x0000000027a40b9e,
   0x0000000079b737ba, 0x000000008bdcb4b9, 0x00000000988c474d, 0x000000006ae7c44e,
   0x00000000be2da0a5, 0x000000004c4623a6, 0x000000005f16d052, 0x00000000ad7d5351,
  };

static UInt64 CsCrc32Map32[2048] =
{
   0x0000000000000000, 0x000000002e34cb9d, 0x000000005c69973a, 0x00000000725d5ca7,
   0x00000000b8d32e74, 0x0000000096e7e5e9, 0x00000000e4bab94e, 0x00000000ca8e72d3,
   0x00000000744a2a19, 0x000000005a7ee184, 0x000000002823bd23, 0x00000000061776be,
   0x00000000cc99046d, 0x00000000e2adcff0, 0x0000000090f09357, 0x00000000bec458ca,
   0x00000000e8945432, 0x00000000c6a09faf, 0x00000000b4fdc308, 0x000000009ac90895,
   0x0000000050477a46, 0x000000007e73b1db, 0x000000000c2eed7c, 0x00000000221a26e1,
   0x000000009cde7e2b, 0x00000000b2eab5b6, 0x00000000c0b7e911, 0x00000000ee83228c,
   0x00000000240d505f, 0x000000000a399bc2, 0x000000007864c765, 0x0000000056500cf8,
   0x00000000d4c4de95, 0x00000000faf01508, 0x0000000088ad49af, 0x00000000a6998232,
   0x000000006c17f0e1, 0x0000000042233b7c, 0x00000000307e67db, 0x000000001e4aac46,
   0x00000000a08ef48c, 0x000000008eba3f11, 0x00000000fce763b6, 0x00000000d2d3a82b,
   0x00000000185ddaf8, 0x0000000036691165, 0x0000000044344dc2, 0x000000006a00865f,
   0x000000003c508aa7, 0x000000001264413a, 0x0000000060391d9d, 0x000000004e0dd600,
   0x000000008483a4d3, 0x00000000aab76f4e, 0x00000000d8ea33e9, 0x00000000f6def874,
   0x00000000481aa0be, 0x00000000662e6b23, 0x0000000014733784, 0x000000003a47fc19,
   0x00000000f0c98eca, 0x00000000defd4557, 0x00000000aca019f0, 0x000000008294d26d,
   0x00000000ac65cbdb, 0x0000000082510046, 0x00000000f00c5ce1, 0x00000000de38977c,
   0x0000000014b6e5af, 0x000000003a822e32, 0x0000000048df7295, 0x0000000066ebb908,
   0x00000000d82fe1c2, 0x00000000f61b2a5f, 0x00000000844676f8, 0x00000000aa72bd65,
   0x0000000060fccfb6, 0x000000004ec8042b, 0x000000003c95588c, 0x0000000012a19311,
   0x0000000044f19fe9, 0x000000006ac55474, 0x00000000189808d3, 0x0000000036acc34e,
   0x00000000fc22b19d, 0x00000000d2167a00, 0x00000000a04b26a7, 0x000000008e7fed3a,
   0x0000000030bbb5f0, 0x000000001e8f7e6d, 0x000000006cd222ca, 0x0000000042e6e957,
   0x0000000088689b84, 0x00000000a65c5019, 0x00000000d4010cbe, 0x00000000fa35c723,
   0x0000000078a1154e, 0x000000005695ded3, 0x0000000024c88274, 0x000000000afc49e9,
   0x00000000c0723b3a, 0x00000000ee46f0a7, 0x000000009c1bac00, 0x00000000b22f679d,
   0x000000000ceb3f57, 0x0000000022dff4ca, 0x000000005082a86d, 0x000000007eb663f0,
   0x00000000b4381123, 0x000000009a0cdabe, 0x00000000e8518619, 0x00000000c6654d84,
   0x000000009035417c, 0x00000000be018ae1, 0x00000000cc5cd646, 0x00000000e2681ddb,
   0x0000000028e66f08, 0x0000000006d2a495, 0x00000000748ff832, 0x000000005abb33af,
   0x00000000e47f6b65, 0x00000000ca4ba0f8, 0x00000000b816fc5f, 0x00000000962237c2,
   0x000000005cac4511, 0x0000000072988e8c, 0x0000000000c5d22b, 0x000000002ef119b6,
   0x000000005d27e147, 0x0000000073132ada, 0x00000000014e767d, 0x000000002f7abde0,
   0x00000000e5f4cf33, 0x00000000cbc004ae, 0x00000000b99d5809, 0x0000000097a99394,
   0x00000000296dcb5e, 0x00000000075900c3, 0x0000000075045c64, 0x000000005b3097f9,
   0x0000000091bee52a, 0x00000000bf8a2eb7, 0x00000000cdd77210, 0x00000000e3e3b98d,
   0x00000000b5b3b575, 0x000000009b877ee8, 0x00000000e9da224f, 0x00000000c7eee9d2,
   0x000000000d609b01, 0x000000002354509c, 0x0000000051090c3b, 0x000000007f3dc7a6,
   0x00000000c1f99f6c, 0x00000000efcd54f1, 0x000000009d900856, 0x00000000b3a4c3cb,
   0x00000000792ab118, 0x00000000571e7a85, 0x0000000025432622, 0x000000000b77edbf,
   0x0000000089e33fd2, 0x00000000a7d7f44f, 0x00000000d58aa8e8, 0x00000000fbbe6375,
   0x00000000313011a6, 0x000000001f04da3b, 0x000000006d59869c, 0x00000000436d4d01,
   0x00000000fda915cb, 0x00000000d39dde56, 0x00000000a1c082f1, 0x000000008ff4496c,
   0x00000000457a3bbf, 0x000000006b4ef022, 0x000000001913ac85, 0x0000000037276718,
   0x0000000061776be0, 0x000000004f43a07d, 0x000000003d1efcda, 0x00000000132a3747,
   0x00000000d9a44594, 0x00000000f7908e09, 0x0000000085cdd2ae, 0x00000000abf91933,
   0x00000000153d41f9, 0x000000003b098a64, 0x000000004954d6c3, 0x0000000067601d5e,
   0x00000000adee6f8d, 0x0000000083daa410, 0x00000000f187f8b7, 0x00000000dfb3332a,
   0x00000000f1422a9c, 0x00000000df76e101, 0x00000000ad2bbda6, 0x00000000831f763b,
   0x00000000499104e8, 0x0000000067a5cf75, 0x0000000015f893d2, 0x000000003bcc584f,
   0x0000000085080085, 0x00000000ab3ccb18, 0x00000000d96197bf, 0x00000000f7555c22,
   0x000000003ddb2ef1, 0x0000000013efe56c, 0x0000000061b2b9cb, 0x000000004f867256,
   0x0000000019d67eae, 0x0000000037e2b533, 0x0000000045bfe994, 0x000000006b8b2209,
   0x00000000a10550da, 0x000000008f319b47, 0x00000000fd6cc7e0, 0x00000000d3580c7d,
   0x000000006d9c54b7, 0x0000000043a89f2a, 0x0000000031f5c38d, 0x000000001fc10810,
   0x00000000d54f7ac3, 0x00000000fb7bb15e, 0x000000008926edf9, 0x00000000a7122664,
   0x000000002586f409, 0x000000000bb23f94, 0x0000000079ef6333, 0x0000000057dba8ae,
   0x000000009d55da7d, 0x00000000b36111e0, 0x00000000c13c4d47, 0x00000000ef0886da,
   0x0000000051ccde10, 0x000000007ff8158d, 0x000000000da5492a, 0x00000000239182b7,
   0x00000000e91ff064, 0x00000000c72b3bf9, 0x00000000b576675e, 0x000000009b42acc3,
   0x00000000cd12a03b, 0x00000000e3266ba6, 0x00000000917b3701, 0x00000000bf4ffc9c,
   0x0000000075c18e4f, 0x000000005bf545d2, 0x0000000029a81975, 0x00000000079cd2e8,
   0x00000000b9588a22, 0x00000000976c41bf, 0x00000000e5311d18, 0x00000000cb05d685,
   0x00000000018ba456, 0x000000002fbf6fcb, 0x000000005de2336c, 0x0000000073d6f8f1,

   0x0000000000000000, 0x000000002dae840f, 0x000000005b5d081e, 0x0000000076f38c11,
   0x00000000b6ba103c, 0x000000009b149433, 0x00000000ede71822, 0x00000000c0499c2d,
   0x0000000068985689, 0x000000004536d286, 0x0000000033c55e97, 0x000000001e6bda98,
   0x00000000de2246b5, 0x00000000f38cc2ba, 0x00000000857f4eab, 0x00000000a8d1caa4,
   0x00000000d130ad12, 0x00000000fc9e291d, 0x000000008a6da50c, 0x00000000a7c32103,
   0x00000000678abd2e, 0x000000004a243921, 0x000000003cd7b530, 0x000000001179313f,
   0x00000000b9a8fb9b, 0x0000000094067f94, 0x00000000e2f5f385, 0x00000000cf5b778a,
   0x000000000f12eba7, 0x0000000022bc6fa8, 0x00000000544fe3b9, 0x0000000079e167b6,
   0x00000000a78d2cd5, 0x000000008a23a8da, 0x00000000fcd024cb, 0x00000000d17ea0c4,
   0x0000000011373ce9, 0x000000003c99b8e6, 0x000000004a6a34f7, 0x0000000067c4b0f8,
   0x00000000cf157a5c, 0x00000000e2bbfe53, 0x0000000094487242, 0x00000000b9e6f64d,
   0x0000000079af6a60, 0x000000005401ee6f, 0x0000000022f2627e, 0x000000000f5ce671,
   0x0000000076bd81c7, 0x000000005b1305c8, 0x000000002de089d9, 0x00000000004e0dd6,
   0x00000000c00791fb, 0x00000000eda915f4, 0x000000009b5a99e5, 0x00000000b6f41dea,
   0x000000001e25d74e, 0x00000000338b5341, 0x000000004578df50, 0x0000000068d65b5f,
   0x00000000a89fc772, 0x000000008531437d, 0x00000000f3c2cf6c, 0x00000000de6c4b63,
   0x000000004af62f5b, 0x000000006758ab54, 0x0000000011ab2745, 0x000000003c05a34a,
   0x00000000fc4c3f67, 0x00000000d1e2bb68, 0x00000000a7113779, 0x000000008abfb376,
   0x00000000226e79d2, 0x000000000fc0fddd, 0x00000000793371cc, 0x00000000549df5c3,
   0x0000000094d469ee, 0x00000000b97aede1, 0x00000000cf8961f0, 0x00000000e227e5ff,
   0x000000009bc68249, 0x00000000b6680646, 0x00000000c09b8a57, 0x00000000ed350e58,
   0x000000002d7c9275, 0x0000000000d2167a, 0x0000000076219a6b, 0x000000005b8f1e64,
   0x00000000f35ed4c0, 0x00000000def050cf, 0x00000000a803dcde, 0x0000000085ad58d1,
   0x0000000045e4c4fc, 0x00000000684a40f3, 0x000000001eb9cce2, 0x00000000331748ed,
   0x00000000ed7b038e, 0x00000000c0d58781, 0x00000000b6260b90, 0x000000009b888f9f,
   0x000000005bc113b2, 0x00000000766f97bd, 0x00000000009c1bac, 0x000000002d329fa3,
   0x0000000085e35507, 0x00000000a84dd108, 0x00000000debe5d19, 0x00000000f310d916,
   0x000000003359453b, 0x000000001ef7c134, 0x0000000068044d25, 0x0000000045aac92a,
   0x000000003c4bae9c, 0x0000000011e52a93, 0x000000006716a682, 0x000000004ab8228d,
   0x000000008af1bea0, 0x00000000a75f3aaf, 0x00000000d1acb6be, 0x00000000fc0232b1,
   0x0000000054d3f815, 0x00000000797d7c1a, 0x000000000f8ef00b, 0x0000000022207404,
   0x00000000e269e829, 0x00000000cfc76c26, 0x00000000b934e037, 0x00000000949a6438,
   0x0000000095ec5eb6, 0x00000000b842dab9, 0x00000000ceb156a8, 0x00000000e31fd2a7,
   0x0000000023564e8a, 0x000000000ef8ca85, 0x00000000780b4694, 0x0000000055a5c29b,
   0x00000000fd74083f, 0x00000000d0da8c30, 0x00000000a6290021, 0x000000008b87842e,
   0x000000004bce1803, 0x0000000066609c0c, 0x000000001093101d, 0x000000003d3d9412,
   0x0000000044dcf3a4, 0x00000000697277ab, 0x000000001f81fbba, 0x00000000322f7fb5,
   0x00000000f266e398, 0x00000000dfc86797, 0x00000000a93beb86, 0x0000000084956f89,
   0x000000002c44a52d, 0x0000000001ea2122, 0x000000007719ad33, 0x000000005ab7293c,
   0x000000009afeb511, 0x00000000b750311e, 0x00000000c1a3bd0f, 0x00000000ec0d3900,
   0x0000000032617263, 0x000000001fcff66c, 0x00000000693c7a7d, 0x000000004492fe72,
   0x0000000084db625f, 0x00000000a975e650, 0x00000000df866a41, 0x00000000f228ee4e,
   0x000000005af924ea, 0x000000007757a0e5, 0x0000000001a42cf4, 0x000000002c0aa8fb,
   0x00000000ec4334d6, 0x00000000c1edb0d9, 0x00000000b71e3cc8, 0x000000009ab0b8c7,
   0x00000000e351df71, 0x00000000ceff5b7e, 0x00000000b80cd76f, 0x0000000095a25360,
   0x0000000055ebcf4d, 0x0000000078454b42, 0x000000000eb6c753, 0x000000002318435c,
   0x000000008bc989f8, 0x00000000a6670df7, 0x00000000d09481e6, 0x00000000fd3a05e9,
   0x000000003d7399c4, 0x0000000010dd1dcb, 0x00000000662e91da, 0x000000004b8015d5,
   0x00000000df1a71ed, 0x00000000f2b4f5e2, 0x00000000844779f3, 0x00000000a9e9fdfc,
   0x0000000069a061d1, 0x00000000440ee5de, 0x0000000032fd69cf, 0x000000001f53edc0,
   0x00000000b7822764, 0x000000009a2ca36b, 0x00000000ecdf2f7a, 0x00000000c171ab75,
   0x0000000001383758, 0x000000002c96b357, 0x000000005a653f46, 0x0000000077cbbb49,
   0x000000000e2adcff, 0x00000000238458f0, 0x000000005577d4e1, 0x0000000078d950ee,
   0x00000000b890ccc3, 0x00000000953e48cc, 0x00000000e3cdc4dd, 0x00000000ce6340d2,
   0x0000000066b28a76, 0x000000004b1c0e79, 0x000000003def8268, 0x0000000010410667,
   0x00000000d0089a4a, 0x00000000fda61e45, 0x000000008b559254, 0x00000000a6fb165b,
   0x0000000078975d38, 0x000000005539d937, 0x0000000023ca5526, 0x000000000e64d129,
   0x00000000ce2d4d04, 0x00000000e383c90b, 0x000000009570451a, 0x00000000b8dec115,
   0x00000000100f0bb1, 0x000000003da18fbe, 0x000000004b5203af, 0x0000000066fc87a0,
   0x00000000a6b51b8d, 0x000000008b1b9f82, 0x00000000fde81393, 0x00000000d046979c,
   0x00000000a9a7f02a, 0x0000000084097425, 0x00000000f2faf834, 0x00000000df547c3b,
   0x000000001f1de016, 0x0000000032b36419, 0x000000004440e808, 0x0000000069ee6c07,
   0x00000000c13fa6a3, 0x00000000ec9122ac, 0x000000009a62aebd, 0x00000000b7cc2ab2,
   0x000000007785b69f, 0x000000005a2b3290, 0x000000002cd8be81, 0x0000000001763a8e,

   0x0000000000000000, 0x000000005e3e92a0, 0x00000000bc7d2540, 0x00000000e243b7e0,
   0x000000007d163c71, 0x000000002328aed1, 0x00000000c16b1931, 0x000000009f558b91,
   0x00000000fa2c78e2, 0x00000000a412ea42, 0x0000000046515da2, 0x00000000186fcf02,
   0x00000000873a4493, 0x00000000d904d633, 0x000000003b4761d3, 0x000000006579f373,
   0x00000000f1b48735, 0x00000000af8a1595, 0x000000004dc9a275, 0x0000000013f730d5,
   0x000000008ca2bb44, 0x00000000d29c29e4, 0x0000000030df9e04, 0x000000006ee10ca4,
   0x000000000b98ffd7, 0x0000000055a66d77, 0x00000000b7e5da97, 0x00000000e9db4837,
   0x00000000768ec3a6, 0x0000000028b05106, 0x00000000caf3e6e6, 0x0000000094cd7446,
   0x00000000e685789b, 0x00000000b8bbea3b, 0x000000005af85ddb, 0x0000000004c6cf7b,
   0x000000009b9344ea, 0x00000000c5add64a, 0x0000000027ee61aa, 0x0000000079d0f30a,
   0x000000001ca90079, 0x00000000429792d9, 0x00000000a0d42539, 0x00000000feeab799,
   0x0000000061bf3c08, 0x000000003f81aea8, 0x00000000ddc21948, 0x0000000083fc8be8,
   0x000000001731ffae, 0x00000000490f6d0e, 0x00000000ab4cdaee, 0x00000000f572484e,
   0x000000006a27c3df, 0x000000003419517f, 0x00000000d65ae69f, 0x000000008864743f,
   0x00000000ed1d874c, 0x00000000b32315ec, 0x000000005160a20c, 0x000000000f5e30ac,
   0x00000000900bbb3d, 0x00000000ce35299d, 0x000000002c769e7d, 0x0000000072480cdd,
   0x00000000c8e687c7, 0x0000000096d81567, 0x00000000749ba287, 0x000000002aa53027,
   0x00000000b5f0bbb6, 0x00000000ebce2916, 0x00000000098d9ef6, 0x0000000057b30c56,
   0x0000000032caff25, 0x000000006cf46d85, 0x000000008eb7da65, 0x00000000d08948c5,
   0x000000004fdcc354, 0x0000000011e251f4, 0x00000000f3a1e614, 0x00000000ad9f74b4,
   0x00000000395200f2, 0x00000000676c9252, 0x00000000852f25b2, 0x00000000db11b712,
   0x0000000044443c83, 0x000000001a7aae23, 0x00000000f83919c3, 0x00000000a6078b63,
   0x00000000c37e7810, 0x000000009d40eab0, 0x000000007f035d50, 0x00000000213dcff0,
   0x00000000be684461, 0x00000000e056d6c1, 0x0000000002156121, 0x000000005c2bf381,
   0x000000002e63ff5c, 0x00000000705d6dfc, 0x00000000921eda1c, 0x00000000cc2048bc,
   0x000000005375c32d, 0x000000000d4b518d, 0x00000000ef08e66d, 0x00000000b13674cd,
   0x00000000d44f87be, 0x000000008a71151e, 0x000000006832a2fe, 0x00000000360c305e,
   0x00000000a959bbcf, 0x00000000f767296f, 0x0000000015249e8f, 0x000000004b1a0c2f,
   0x00000000dfd77869, 0x0000000081e9eac9, 0x0000000063aa5d29, 0x000000003d94cf89,
   0x00000000a2c14418, 0x00000000fcffd6b8, 0x000000001ebc6158, 0x000000004082f3f8,
   0x0000000025fb008b, 0x000000007bc5922b, 0x00000000998625cb, 0x00000000c7b8b76b,
   0x0000000058ed3cfa, 0x0000000006d3ae5a, 0x00000000e49019ba, 0x00000000baae8b1a,
   0x000000009421797f, 0x00000000ca1febdf, 0x00000000285c5c3f, 0x000000007662ce9f,
   0x00000000e937450e, 0x00000000b709d7ae, 0x00000000554a604e, 0x000000000b74f2ee,
   0x000000006e0d019d, 0x000000003033933d, 0x00000000d27024dd, 0x000000008c4eb67d,
   0x00000000131b3dec, 0x000000004d25af4c, 0x00000000af6618ac, 0x00000000f1588a0c,
   0x000000006595fe4a, 0x000000003bab6cea, 0x00000000d9e8db0a, 0x0000000087d649aa,
   0x000000001883c23b, 0x0000000046bd509b, 0x00000000a4fee77b, 0x00000000fac075db,
   0x000000009fb986a8, 0x00000000c1871408, 0x0000000023c4a3e8, 0x000000007dfa3148,
   0x00000000e2afbad9, 0x00000000bc912879, 0x000000005ed29f99, 0x0000000000ec0d39,
   0x0000000072a401e4, 0x000000002c9a9344, 0x00000000ced924a4, 0x0000000090e7b604,
   0x000000000fb23d95, 0x00000000518caf35, 0x00000000b3cf18d5, 0x00000000edf18a75,
   0x0000000088887906, 0x00000000d6b6eba6, 0x0000000034f55c46, 0x000000006acbcee6,
   0x00000000f59e4577, 0x00000000aba0d7d7, 0x0000000049e36037, 0x0000000017ddf297,
   0x00000000831086d1, 0x00000000dd2e1471, 0x000000003f6da391, 0x0000000061533131,
   0x00000000fe06baa0, 0x00000000a0382800, 0x00000000427b9fe0, 0x000000001c450d40,
   0x00000000793cfe33, 0x0000000027026c93, 0x00000000c541db73, 0x000000009b7f49d3,
   0x00000000042ac242, 0x000000005a1450e2, 0x00000000b857e702, 0x00000000e66975a2,
   0x000000005cc7feb8, 0x0000000002f96c18, 0x00000000e0badbf8, 0x00000000be844958,
   0x0000000021d1c2c9, 0x000000007fef5069, 0x000000009dace789, 0x00000000c3927529,
   0x00000000a6eb865a, 0x00000000f8d514fa, 0x000000001a96a31a, 0x0000000044a831ba,
   0x00000000dbfdba2b, 0x0000000085c3288b, 0x0000000067809f6b, 0x0000000039be0dcb,
   0x00000000ad73798d, 0x00000000f34deb2d, 0x00000000110e5ccd, 0x000000004f30ce6d,
   0x00000000d06545fc, 0x000000008e5bd75c, 0x000000006c1860bc, 0x000000003226f21c,
   0x00000000575f016f, 0x00000000096193cf, 0x00000000eb22242f, 0x00000000b51cb68f,
   0x000000002a493d1e, 0x000000007477afbe, 0x000000009634185e, 0x00000000c80a8afe,
   0x00000000ba428623, 0x00000000e47c1483, 0x00000000063fa363, 0x00000000580131c3,
   0x00000000c754ba52, 0x00000000996a28f2, 0x000000007b299f12, 0x0000000025170db2,
   0x00000000406efec1, 0x000000001e506c61, 0x00000000fc13db81, 0x00000000a22d4921,
   0x000000003d78c2b0, 0x0000000063465010, 0x000000008105e7f0, 0x00000000df3b7550,
   0x000000004bf60116, 0x0000000015c893b6, 0x00000000f78b2456, 0x00000000a9b5b6f6,
   0x0000000036e03d67, 0x0000000068deafc7, 0x000000008a9d1827, 0x00000000d4a38a87,
   0x00000000b1da79f4, 0x00000000efe4eb54, 0x000000000da75cb4, 0x000000005399ce14,
   0x00000000cccc4585, 0x0000000092f2d725, 0x0000000070b160c5, 0x000000002e8ff265,

   0x0000000000000000, 0x00000000a2158b34, 0x0000000041c76099, 0x00000000e3d2ebad,
   0x00000000838ec132, 0x00000000219b4a06, 0x00000000c249a1ab, 0x00000000605c2a9f,
   0x0000000002f1f495, 0x00000000a0e47fa1, 0x000000004336940c, 0x00000000e1231f38,
   0x00000000817f35a7, 0x00000000236abe93, 0x00000000c0b8553e, 0x0000000062adde0a,
   0x0000000005e3e92a, 0x00000000a7f6621e, 0x00000000442489b3, 0x00000000e6310287,
   0x00000000866d2818, 0x000000002478a32c, 0x00000000c7aa4881, 0x0000000065bfc3b5,
   0x0000000007121dbf, 0x00000000a507968b, 0x0000000046d57d26, 0x00000000e4c0f612,
   0x00000000849cdc8d, 0x00000000268957b9, 0x00000000c55bbc14, 0x00000000674e3720,
   0x000000000bc7d254, 0x00000000a9d25960, 0x000000004a00b2cd, 0x00000000e81539f9,
   0x0000000088491366, 0x000000002a5c9852, 0x00000000c98e73ff, 0x000000006b9bf8cb,
   0x00000000093626c1, 0x00000000ab23adf5, 0x0000000048f14658, 0x00000000eae4cd6c,
   0x000000008ab8e7f3, 0x0000000028ad6cc7, 0x00000000cb7f876a, 0x00000000696a0c5e,
   0x000000000e243b7e, 0x00000000ac31b04a, 0x000000004fe35be7, 0x00000000edf6d0d3,
   0x000000008daafa4c, 0x000000002fbf7178, 0x00000000cc6d9ad5, 0x000000006e7811e1,
   0x000000000cd5cfeb, 0x00000000aec044df, 0x000000004d12af72, 0x00000000ef072446,
   0x000000008f5b0ed9, 0x000000002d4e85ed, 0x00000000ce9c6e40, 0x000000006c89e574,
   0x00000000178fa4a8, 0x00000000b59a2f9c, 0x000000005648c431, 0x00000000f45d4f05,
   0x000000009401659a, 0x000000003614eeae, 0x00000000d5c60503, 0x0000000077d38e37,
   0x00000000157e503d, 0x00000000b76bdb09, 0x0000000054b930a4, 0x00000000f6acbb90,
   0x0000000096f0910f, 0x0000000034e51a3b, 0x00000000d737f196, 0x0000000075227aa2,
   0x00000000126c4d82, 0x00000000b079c6b6, 0x0000000053ab2d1b, 0x00000000f1bea62f,
   0x0000000091e28cb0, 0x0000000033f70784, 0x00000000d025ec29, 0x000000007230671d,
   0x00000000109db917, 0x00000000b2883223, 0x00000000515ad98e, 0x00000000f34f52ba,
   0x0000000093137825, 0x000000003106f311, 0x00000000d2d418bc, 0x0000000070c19388,
   0x000000001c4876fc, 0x00000000be5dfdc8, 0x000000005d8f1665, 0x00000000ff9a9d51,
   0x000000009fc6b7ce, 0x000000003dd33cfa, 0x00000000de01d757, 0x000000007c145c63,
   0x000000001eb98269, 0x00000000bcac095d, 0x000000005f7ee2f0, 0x00000000fd6b69c4,
   0x000000009d37435b, 0x000000003f22c86f, 0x00000000dcf023c2, 0x000000007ee5a8f6,
   0x0000000019ab9fd6, 0x00000000bbbe14e2, 0x00000000586cff4f, 0x00000000fa79747b,
   0x000000009a255ee4, 0x000000003830d5d0, 0x00000000dbe23e7d, 0x0000000079f7b549,
   0x000000001b5a6b43, 0x00000000b94fe077, 0x000000005a9d0bda, 0x00000000f88880ee,
   0x0000000098d4aa71, 0x000000003ac12145, 0x00000000d913cae8, 0x000000007b0641dc,
   0x000000002f1f4950, 0x000000008d0ac264, 0x000000006ed829c9, 0x00000000cccda2fd,
   0x00000000ac918862, 0x000000000e840356, 0x00000000ed56e8fb, 0x000000004f4363cf,
   0x000000002deebdc5, 0x000000008ffb36f1, 0x000000006c29dd5c, 0x00000000ce3c5668,
   0x00000000ae607cf7, 0x000000000c75f7c3, 0x00000000efa71c6e, 0x000000004db2975a,
   0x000000002afca07a, 0x0000000088e92b4e, 0x000000006b3bc0e3, 0x00000000c92e4bd7,
   0x00000000a9726148, 0x000000000b67ea7c, 0x00000000e8b501d1, 0x000000004aa08ae5,
   0x00000000280d54ef, 0x000000008a18dfdb, 0x0000000069ca3476, 0x00000000cbdfbf42,
   0x00000000ab8395dd, 0x0000000009961ee9, 0x00000000ea44f544, 0x0000000048517e70,
   0x0000000024d89b04, 0x0000000086cd1030, 0x00000000651ffb9d, 0x00000000c70a70a9,
   0x00000000a7565a36, 0x000000000543d102, 0x00000000e6913aaf, 0x000000004484b19b,
   0x0000000026296f91, 0x00000000843ce4a5, 0x0000000067ee0f08, 0x00000000c5fb843c,
   0x00000000a5a7aea3, 0x0000000007b22597, 0x00000000e460ce3a, 0x000000004675450e,
   0x00000000213b722e, 0x00000000832ef91a, 0x0000000060fc12b7, 0x00000000c2e99983,
   0x00000000a2b5b31c, 0x0000000000a03828, 0x00000000e372d385, 0x00000000416758b1,
   0x0000000023ca86bb, 0x0000000081df0d8f, 0x00000000620de622, 0x00000000c0186d16,
   0x00000000a0444789, 0x000000000251ccbd, 0x00000000e1832710, 0x000000004396ac24,
   0x000000003890edf8, 0x000000009a8566cc, 0x0000000079578d61, 0x00000000db420655,
   0x00000000bb1e2cca, 0x00000000190ba7fe, 0x00000000fad94c53, 0x0000000058ccc767,
   0x000000003a61196d, 0x0000000098749259, 0x000000007ba679f4, 0x00000000d9b3f2c0,
   0x00000000b9efd85f, 0x000000001bfa536b, 0x00000000f828b8c6, 0x000000005a3d33f2,
   0x000000003d7304d2, 0x000000009f668fe6, 0x000000007cb4644b, 0x00000000dea1ef7f,
   0x00000000befdc5e0, 0x000000001ce84ed4, 0x00000000ff3aa579, 0x000000005d2f2e4d,
   0x000000003f82f047, 0x000000009d977b73, 0x000000007e4590de, 0x00000000dc501bea,
   0x00000000bc0c3175, 0x000000001e19ba41, 0x00000000fdcb51ec, 0x000000005fdedad8,
   0x0000000033573fac, 0x000000009142b498, 0x0000000072905f35, 0x00000000d085d401,
   0x00000000b0d9fe9e, 0x0000000012cc75aa, 0x00000000f11e9e07, 0x00000000530b1533,
   0x0000000031a6cb39, 0x0000000093b3400d, 0x000000007061aba0, 0x00000000d2742094,
   0x00000000b2280a0b, 0x00000000103d813f, 0x00000000f3ef6a92, 0x0000000051fae1a6,
   0x0000000036b4d686, 0x0000000094a15db2, 0x000000007773b61f, 0x00000000d5663d2b,
   0x00000000b53a17b4, 0x00000000172f9c80, 0x00000000f4fd772d, 0x0000000056e8fc19,
   0x0000000034452213, 0x000000009650a927, 0x000000007582428a, 0x00000000d797c9be,
   0x00000000b7cbe321, 0x0000000015de6815, 0x00000000f60c83b8, 0x000000005419088c,

   0x0000000000000000, 0x00000000f7dbcb25, 0x00000000ea5be0bb, 0x000000001d802b9e,
   0x00000000d15bb787, 0x0000000026807ca2, 0x000000003b00573c, 0x00000000ccdb9c19,
   0x00000000a75b19ff, 0x000000005080d2da, 0x000000004d00f944, 0x00000000badb3261,
   0x000000007600ae78, 0x0000000081db655d, 0x000000009c5b4ec3, 0x000000006b8085e6,
   0x000000004b5a450f, 0x00000000bc818e2a, 0x00000000a101a5b4, 0x0000000056da6e91,
   0x000000009a01f288, 0x000000006dda39ad, 0x00000000705a1233, 0x000000008781d916,
   0x00000000ec015cf0, 0x000000001bda97d5, 0x00000000065abc4b, 0x00000000f181776e,
   0x000000003d5aeb77, 0x00000000ca812052, 0x00000000d7010bcc, 0x0000000020dac0e9,
   0x0000000096b48a1e, 0x00000000616f413b, 0x000000007cef6aa5, 0x000000008b34a180,
   0x0000000047ef3d99, 0x00000000b034f6bc, 0x00000000adb4dd22, 0x000000005a6f1607,
   0x0000000031ef93e1, 0x00000000c63458c4, 0x00000000dbb4735a, 0x000000002c6fb87f,
   0x00000000e0b42466, 0x00000000176fef43, 0x000000000aefc4dd, 0x00000000fd340ff8,
   0x00000000ddeecf11, 0x000000002a350434, 0x0000000037b52faa, 0x00000000c06ee48f,
   0x000000000cb57896, 0x00000000fb6eb3b3, 0x00000000e6ee982d, 0x0000000011355308,
   0x000000007ab5d6ee, 0x000000008d6e1dcb, 0x0000000090ee3655, 0x000000006735fd70,
   0x00000000abee6169, 0x000000005c35aa4c, 0x0000000041b581d2, 0x00000000b66e4af7,
   0x00000000288562cd, 0x00000000df5ea9e8, 0x00000000c2de8276, 0x0000000035054953,
   0x00000000f9ded54a, 0x000000000e051e6f, 0x00000000138535f1, 0x00000000e45efed4,
   0x000000008fde7b32, 0x000000007805b017, 0x0000000065859b89, 0x00000000925e50ac,
   0x000000005e85ccb5, 0x00000000a95e0790, 0x00000000b4de2c0e, 0x000000004305e72b,
   0x0000000063df27c2, 0x000000009404ece7, 0x000000008984c779, 0x000000007e5f0c5c,
   0x00000000b2849045, 0x00000000455f5b60, 0x0000000058df70fe, 0x00000000af04bbdb,
   0x00000000c4843e3d, 0x00000000335ff518, 0x000000002edfde86, 0x00000000d90415a3,
   0x0000000015df89ba, 0x00000000e204429f, 0x00000000ff846901, 0x00000000085fa224,
   0x00000000be31e8d3, 0x0000000049ea23f6, 0x00000000546a0868, 0x00000000a3b1c34d,
   0x000000006f6a5f54, 0x0000000098b19471, 0x000000008531bfef, 0x0000000072ea74ca,
   0x00000000196af12c, 0x00000000eeb13a09, 0x00000000f3311197, 0x0000000004eadab2,
   0x00000000c83146ab, 0x000000003fea8d8e, 0x00000000226aa610, 0x00000000d5b16d35,
   0x00000000f56baddc, 0x0000000002b066f9, 0x000000001f304d67, 0x00000000e8eb8642,
   0x0000000024301a5b, 0x00000000d3ebd17e, 0x00000000ce6bfae0, 0x0000000039b031c5,
   0x000000005230b423, 0x00000000a5eb7f06, 0x00000000b86b5498, 0x000000004fb09fbd,
   0x00000000836b03a4, 0x0000000074b0c881, 0x000000006930e31f, 0x000000009eeb283a,
   0x00000000510ac59a, 0x00000000a6d10ebf, 0x00000000bb512521, 0x000000004c8aee04,
   0x000000008051721d, 0x00000000778ab938, 0x000000006a0a92a6, 0x000000009dd15983,
   0x00000000f651dc65, 0x00000000018a1740, 0x000000001c0a3cde, 0x00000000ebd1f7fb,
   0x00000000270a6be2, 0x00000000d0d1a0c7, 0x00000000cd518b59, 0x000000003a8a407c,
   0x000000001a508095, 0x00000000ed8b4bb0, 0x00000000f00b602e, 0x0000000007d0ab0b,
   0x00000000cb0b3712, 0x000000003cd0fc37, 0x000000002150d7a9, 0x00000000d68b1c8c,
   0x00000000bd0b996a, 0x000000004ad0524f, 0x00000000575079d1, 0x00000000a08bb2f4,
   0x000000006c502eed, 0x000000009b8be5c8, 0x00000000860bce56, 0x0000000071d00573,
   0x00000000c7be4f84, 0x00000000306584a1, 0x000000002de5af3f, 0x00000000da3e641a,
   0x0000000016e5f803, 0x00000000e13e3326, 0x00000000fcbe18b8, 0x000000000b65d39d,
   0x0000000060e5567b, 0x00000000973e9d5e, 0x000000008abeb6c0, 0x000000007d657de5,
   0x00000000b1bee1fc, 0x0000000046652ad9, 0x000000005be50147, 0x00000000ac3eca62,
   0x000000008ce40a8b, 0x000000007b3fc1ae, 0x0000000066bfea30, 0x0000000091642115,
   0x000000005dbfbd0c, 0x00000000aa647629, 0x00000000b7e45db7, 0x00000000403f9692,
   0x000000002bbf1374, 0x00000000dc64d851, 0x00000000c1e4f3cf, 0x00000000363f38ea,
   0x00000000fae4a4f3, 0x000000000d3f6fd6, 0x0000000010bf4448, 0x00000000e7648f6d,
   0x00000000798fa757, 0x000000008e546c72, 0x0000000093d447ec, 0x00000000640f8cc9,
   0x00000000a8d410d0, 0x000000005f0fdbf5, 0x00000000428ff06b, 0x00000000b5543b4e,
   0x00000000ded4bea8, 0x00000000290f758d, 0x00000000348f5e13, 0x00000000c3549536,
   0x000000000f8f092f, 0x00000000f854c20a, 0x00000000e5d4e994, 0x00000000120f22b1,
   0x0000000032d5e258, 0x00000000c50e297d, 0x00000000d88e02e3, 0x000000002f55c9c6,
   0x00000000e38e55df, 0x0000000014559efa, 0x0000000009d5b564, 0x00000000fe0e7e41,
   0x00000000958efba7, 0x0000000062553082, 0x000000007fd51b1c, 0x00000000880ed039,
   0x0000000044d54c20, 0x00000000b30e8705, 0x00000000ae8eac9b, 0x00000000595567be,
   0x00000000ef3b2d49, 0x0000000018e0e66c, 0x000000000560cdf2, 0x00000000f2bb06d7,
   0x000000003e609ace, 0x00000000c9bb51eb, 0x00000000d43b7a75, 0x0000000023e0b150,
   0x00000000486034b6, 0x00000000bfbbff93, 0x00000000a23bd40d, 0x0000000055e01f28,
   0x00000000993b8331, 0x000000006ee04814, 0x000000007360638a, 0x0000000084bba8af,
   0x00000000a4616846, 0x0000000053baa363, 0x000000004e3a88fd, 0x00000000b9e143d8,
   0x00000000753adfc1, 0x0000000082e114e4, 0x000000009f613f7a, 0x0000000068baf45f,
   0x00000000033a71b9, 0x00000000f4e1ba9c, 0x00000000e9619102, 0x000000001eba5a27,
   0x00000000d261c63e, 0x0000000025ba0d1b, 0x00000000383a2685, 0x00000000cfe1eda0,

   0x0000000000000000, 0x0000000015bb4109, 0x000000002b768212, 0x000000003ecdc31b,
   0x0000000056ed0424, 0x000000004356452d, 0x000000007d9b8636, 0x000000006820c73f,
   0x00000000adda0848, 0x00000000b8614941, 0x0000000086ac8a5a, 0x000000009317cb53,
   0x00000000fb370c6c, 0x00000000ee8c4d65, 0x00000000d0418e7e, 0x00000000c5facf77,
   0x000000005e586661, 0x000000004be32768, 0x00000000752ee473, 0x000000006095a57a,
   0x0000000008b56245, 0x000000001d0e234c, 0x0000000023c3e057, 0x000000003678a15e,
   0x00000000f3826e29, 0x00000000e6392f20, 0x00000000d8f4ec3b, 0x00000000cd4fad32,
   0x00000000a56f6a0d, 0x00000000b0d42b04, 0x000000008e19e81f, 0x000000009ba2a916,
   0x00000000bcb0ccc2, 0x00000000a90b8dcb, 0x0000000097c64ed0, 0x00000000827d0fd9,
   0x00000000ea5dc8e6, 0x00000000ffe689ef, 0x00000000c12b4af4, 0x00000000d4900bfd,
   0x00000000116ac48a, 0x0000000004d18583, 0x000000003a1c4698, 0x000000002fa70791,
   0x000000004787c0ae, 0x00000000523c81a7, 0x000000006cf142bc, 0x00000000794a03b5,
   0x00000000e2e8aaa3, 0x00000000f753ebaa, 0x00000000c99e28b1, 0x00000000dc2569b8,
   0x00000000b405ae87, 0x00000000a1beef8e, 0x000000009f732c95, 0x000000008ac86d9c,
   0x000000004f32a2eb, 0x000000005a89e3e2, 0x00000000644420f9, 0x0000000071ff61f0,
   0x0000000019dfa6cf, 0x000000000c64e7c6, 0x0000000032a924dd, 0x00000000271265d4,
   0x000000007c8def75, 0x000000006936ae7c, 0x0000000057fb6d67, 0x0000000042402c6e,
   0x000000002a60eb51, 0x000000003fdbaa58, 0x0000000001166943, 0x0000000014ad284a,
   0x00000000d157e73d, 0x00000000c4eca634, 0x00000000fa21652f, 0x00000000ef9a2426,
   0x0000000087bae319, 0x000000009201a210, 0x00000000accc610b, 0x00000000b9772002,
   0x0000000022d58914, 0x00000000376ec81d, 0x0000000009a30b06, 0x000000001c184a0f,
   0x0000000074388d30, 0x000000006183cc39, 0x000000005f4e0f22, 0x000000004af54e2b,
   0x000000008f0f815c, 0x000000009ab4c055, 0x00000000a479034e, 0x00000000b1c24247,
   0x00000000d9e28578, 0x00000000cc59c471, 0x00000000f294076a, 0x00000000e72f4663,
   0x00000000c03d23b7, 0x00000000d58662be, 0x00000000eb4ba1a5, 0x00000000fef0e0ac,
   0x0000000096d02793, 0x00000000836b669a, 0x00000000bda6a581, 0x00000000a81de488,
   0x000000006de72bff, 0x00000000785c6af6, 0x000000004691a9ed, 0x00000000532ae8e4,
   0x000000003b0a2fdb, 0x000000002eb16ed2, 0x00000000107cadc9, 0x0000000005c7ecc0,
   0x000000009e6545d6, 0x000000008bde04df, 0x00000000b513c7c4, 0x00000000a0a886cd,
   0x00000000c88841f2, 0x00000000dd3300fb, 0x00000000e3fec3e0, 0x00000000f64582e9,
   0x0000000033bf4d9e, 0x0000000026040c97, 0x0000000018c9cf8c, 0x000000000d728e85,
   0x00000000655249ba, 0x0000000070e908b3, 0x000000004e24cba8, 0x000000005b9f8aa1,
   0x00000000f91bdeea, 0x00000000eca09fe3, 0x00000000d26d5cf8, 0x00000000c7d61df1,
   0x00000000aff6dace, 0x00000000ba4d9bc7, 0x00000000848058dc, 0x00000000913b19d5,
   0x0000000054c1d6a2, 0x00000000417a97ab, 0x000000007fb754b0, 0x000000006a0c15b9,
   0x00000000022cd286, 0x000000001797938f, 0x00000000295a5094, 0x000000003ce1119d,
   0x00000000a743b88b, 0x00000000b2f8f982, 0x000000008c353a99, 0x00000000998e7b90,
   0x00000000f1aebcaf, 0x00000000e415fda6, 0x00000000dad83ebd, 0x00000000cf637fb4,
   0x000000000a99b0c3, 0x000000001f22f1ca, 0x0000000021ef32d1, 0x00000000345473d8,
   0x000000005c74b4e7, 0x0000000049cff5ee, 0x00000000770236f5, 0x0000000062b977fc,
   0x0000000045ab1228, 0x0000000050105321, 0x000000006edd903a, 0x000000007b66d133,
   0x000000001346160c, 0x0000000006fd5705, 0x000000003830941e, 0x000000002d8bd517,
   0x00000000e8711a60, 0x00000000fdca5b69, 0x00000000c3079872, 0x00000000d6bcd97b,
   0x00000000be9c1e44, 0x00000000ab275f4d, 0x0000000095ea9c56, 0x000000008051dd5f,
   0x000000001bf37449, 0x000000000e483540, 0x000000003085f65b, 0x00000000253eb752,
   0x000000004d1e706d, 0x0000000058a53164, 0x000000006668f27f, 0x0000000073d3b376,
   0x00000000b6297c01, 0x00000000a3923d08, 0x000000009d5ffe13, 0x0000000088e4bf1a,
   0x00000000e0c47825, 0x00000000f57f392c, 0x00000000cbb2fa37, 0x00000000de09bb3e,
   0x000000008596319f, 0x00000000902d7096, 0x00000000aee0b38d, 0x00000000bb5bf284,
   0x00000000d37b35bb, 0x00000000c6c074b2, 0x00000000f80db7a9, 0x00000000edb6f6a0,
   0x00000000284c39d7, 0x000000003df778de, 0x00000000033abbc5, 0x000000001681facc,
   0x000000007ea13df3, 0x000000006b1a7cfa, 0x0000000055d7bfe1, 0x00000000406cfee8,
   0x00000000dbce57fe, 0x00000000ce7516f7, 0x00000000f0b8d5ec, 0x00000000e50394e5,
   0x000000008d2353da, 0x00000000989812d3, 0x00000000a655d1c8, 0x00000000b3ee90c1,
   0x0000000076145fb6, 0x0000000063af1ebf, 0x000000005d62dda4, 0x0000000048d99cad,
   0x0000000020f95b92, 0x0000000035421a9b, 0x000000000b8fd980, 0x000000001e349889,
   0x000000003926fd5d, 0x000000002c9dbc54, 0x0000000012507f4f, 0x0000000007eb3e46,
   0x000000006fcbf979, 0x000000007a70b870, 0x0000000044bd7b6b, 0x0000000051063a62,
   0x0000000094fcf515, 0x000000008147b41c, 0x00000000bf8a7707, 0x00000000aa31360e,
   0x00000000c211f131, 0x00000000d7aab038, 0x00000000e9677323, 0x00000000fcdc322a,
   0x00000000677e9b3c, 0x0000000072c5da35, 0x000000004c08192e, 0x0000000059b35827,
   0x0000000031939f18, 0x000000002428de11, 0x000000001ae51d0a, 0x000000000f5e5c03,
   0x00000000caa49374, 0x00000000df1fd27d, 0x00000000e1d21166, 0x00000000f469506f,
   0x000000009c499750, 0x0000000089f2d659, 0x00000000b73f1542, 0x00000000a284544b,

   0x0000000000000000, 0x0000000078a7608d, 0x00000000f14ec11a, 0x0000000089e9a197,
   0x00000000e771f4c5, 0x000000009fd69448, 0x00000000163f35df, 0x000000006e985552,
   0x00000000cb0f9f7b, 0x00000000b3a8fff6, 0x000000003a415e61, 0x0000000042e63eec,
   0x000000002c7e6bbe, 0x0000000054d90b33, 0x00000000dd30aaa4, 0x00000000a597ca29,
   0x0000000093f34807, 0x00000000eb54288a, 0x0000000062bd891d, 0x000000001a1ae990,
   0x000000007482bcc2, 0x000000000c25dc4f, 0x0000000085cc7dd8, 0x00000000fd6b1d55,
   0x0000000058fcd77c, 0x00000000205bb7f1, 0x00000000a9b21666, 0x00000000d11576eb,
   0x00000000bf8d23b9, 0x00000000c72a4334, 0x000000004ec3e2a3, 0x000000003664822e,
   0x00000000220ae6ff, 0x000000005aad8672, 0x00000000d34427e5, 0x00000000abe34768,
   0x00000000c57b123a, 0x00000000bddc72b7, 0x000000003435d320, 0x000000004c92b3ad,
   0x00000000e9057984, 0x0000000091a21909, 0x00000000184bb89e, 0x0000000060ecd813,
   0x000000000e748d41, 0x0000000076d3edcc, 0x00000000ff3a4c5b, 0x00000000879d2cd6,
   0x00000000b1f9aef8, 0x00000000c95ece75, 0x0000000040b76fe2, 0x0000000038100f6f,
   0x0000000056885a3d, 0x000000002e2f3ab0, 0x00000000a7c69b27, 0x00000000df61fbaa,
   0x000000007af63183, 0x000000000251510e, 0x000000008bb8f099, 0x00000000f31f9014,
   0x000000009d87c546, 0x00000000e520a5cb, 0x000000006cc9045c, 0x00000000146e64d1,
   0x000000004415cdfe, 0x000000003cb2ad73, 0x00000000b55b0ce4, 0x00000000cdfc6c69,
   0x00000000a364393b, 0x00000000dbc359b6, 0x00000000522af821, 0x000000002a8d98ac,
   0x000000008f1a5285, 0x00000000f7bd3208, 0x000000007e54939f, 0x0000000006f3f312,
   0x00000000686ba640, 0x0000000010ccc6cd, 0x000000009925675a, 0x00000000e18207d7,
   0x00000000d7e685f9, 0x00000000af41e574, 0x0000000026a844e3, 0x000000005e0f246e,
   0x000000003097713c, 0x00000000483011b1, 0x00000000c1d9b026, 0x00000000b97ed0ab,
   0x000000001ce91a82, 0x00000000644e7a0f, 0x00000000eda7db98, 0x000000009500bb15,
   0x00000000fb98ee47, 0x00000000833f8eca, 0x000000000ad62f5d, 0x0000000072714fd0,
   0x00000000661f2b01, 0x000000001eb84b8c, 0x000000009751ea1b, 0x00000000eff68a96,
   0x00000000816edfc4, 0x00000000f9c9bf49, 0x0000000070201ede, 0x0000000008877e53,
   0x00000000ad10b47a, 0x00000000d5b7d4f7, 0x000000005c5e7560, 0x0000000024f915ed,
   0x000000004a6140bf, 0x0000000032c62032, 0x00000000bb2f81a5, 0x00000000c388e128,
   0x00000000f5ec6306, 0x000000008d4b038b, 0x0000000004a2a21c, 0x000000007c05c291,
   0x00000000129d97c3, 0x000000006a3af74e, 0x00000000e3d356d9, 0x000000009b743654,
   0x000000003ee3fc7d, 0x0000000046449cf0, 0x00000000cfad3d67, 0x00000000b70a5dea,
   0x00000000d99208b8, 0x00000000a1356835, 0x0000000028dcc9a2, 0x00000000507ba92f,
   0x00000000882b9bfc, 0x00000000f08cfb71, 0x0000000079655ae6, 0x0000000001c23a6b,
   0x000000006f5a6f39, 0x0000000017fd0fb4, 0x000000009e14ae23, 0x00000000e6b3ceae,
   0x0000000043240487, 0x000000003b83640a, 0x00000000b26ac59d, 0x00000000cacda510,
   0x00000000a455f042, 0x00000000dcf290cf, 0x00000000551b3158, 0x000000002dbc51d5,
   0x000000001bd8d3fb, 0x00000000637fb376, 0x00000000ea9612e1, 0x000000009231726c,
   0x00000000fca9273e, 0x00000000840e47b3, 0x000000000de7e624, 0x00000000754086a9,
   0x00000000d0d74c80, 0x00000000a8702c0d, 0x0000000021998d9a, 0x00000000593eed17,
   0x0000000037a6b845, 0x000000004f01d8c8, 0x00000000c6e8795f, 0x00000000be4f19d2,
   0x00000000aa217d03, 0x00000000d2861d8e, 0x000000005b6fbc19, 0x0000000023c8dc94,
   0x000000004d5089c6, 0x0000000035f7e94b, 0x00000000bc1e48dc, 0x00000000c4b92851,
   0x00000000612ee278, 0x00000000198982f5, 0x0000000090602362, 0x00000000e8c743ef,
   0x00000000865f16bd, 0x00000000fef87630, 0x000000007711d7a7, 0x000000000fb6b72a,
   0x0000000039d23504, 0x0000000041755589, 0x00000000c89cf41e, 0x00000000b03b9493,
   0x00000000dea3c1c1, 0x00000000a604a14c, 0x000000002fed00db, 0x00000000574a6056,
   0x00000000f2ddaa7f, 0x000000008a7acaf2, 0x0000000003936b65, 0x000000007b340be8,
   0x0000000015ac5eba, 0x000000006d0b3e37, 0x00000000e4e29fa0, 0x000000009c45ff2d,
   0x00000000cc3e5602, 0x00000000b499368f, 0x000000003d709718, 0x0000000045d7f795,
   0x000000002b4fa2c7, 0x0000000053e8c24a, 0x00000000da0163dd, 0x00000000a2a60350,
   0x000000000731c979, 0x000000007f96a9f4, 0x00000000f67f0863, 0x000000008ed868ee,
   0x00000000e0403dbc, 0x0000000098e75d31, 0x00000000110efca6, 0x0000000069a99c2b,
   0x000000005fcd1e05, 0x00000000276a7e88, 0x00000000ae83df1f, 0x00000000d624bf92,
   0x00000000b8bceac0, 0x00000000c01b8a4d, 0x0000000049f22bda, 0x0000000031554b57,
   0x0000000094c2817e, 0x00000000ec65e1f3, 0x00000000658c4064, 0x000000001d2b20e9,
   0x0000000073b375bb, 0x000000000b141536, 0x0000000082fdb4a1, 0x00000000fa5ad42c,
   0x00000000ee34b0fd, 0x000000009693d070, 0x000000001f7a71e7, 0x0000000067dd116a,
   0x0000000009454438, 0x0000000071e224b5, 0x00000000f80b8522, 0x0000000080ace5af,
   0x00000000253b2f86, 0x000000005d9c4f0b, 0x00000000d475ee9c, 0x00000000acd28e11,
   0x00000000c24adb43, 0x00000000baedbbce, 0x0000000033041a59, 0x000000004ba37ad4,
   0x000000007dc7f8fa, 0x0000000005609877, 0x000000008c8939e0, 0x00000000f42e596d,
   0x000000009ab60c3f, 0x00000000e2116cb2, 0x000000006bf8cd25, 0x00000000135fada8,
   0x00000000b6c86781, 0x00000000ce6f070c, 0x000000004786a69b, 0x000000003f21c616,
   0x0000000051b99344, 0x00000000291ef3c9, 0x00000000a0f7525e, 0x00000000d85032d3,

   0x0000000000000000, 0x000000003da6d0cb, 0x000000007b4da196, 0x0000000046eb715d,
   0x00000000f69b432c, 0x00000000cb3d93e7, 0x000000008dd6e2ba, 0x00000000b0703271,
   0x00000000e8daf0a9, 0x00000000d57c2062, 0x000000009397513f, 0x00000000ae3181f4,
   0x000000001e41b385, 0x0000000023e7634e, 0x00000000650c1213, 0x0000000058aac2d8,
   0x00000000d45997a3, 0x00000000e9ff4768, 0x00000000af143635, 0x0000000092b2e6fe,
   0x0000000022c2d48f, 0x000000001f640444, 0x00000000598f7519, 0x000000006429a5d2,
   0x000000003c83670a, 0x000000000125b7c1, 0x0000000047cec69c, 0x000000007a681657,
   0x00000000ca182426, 0x00000000f7bef4ed, 0x00000000b15585b0, 0x000000008cf3557b,
   0x00000000ad5f59b7, 0x0000000090f9897c, 0x00000000d612f821, 0x00000000ebb428ea,
   0x000000005bc41a9b, 0x000000006662ca50, 0x000000002089bb0d, 0x000000001d2f6bc6,
   0x000000004585a91e, 0x00000000782379d5, 0x000000003ec80888, 0x00000000036ed843,
   0x00000000b31eea32, 0x000000008eb83af9, 0x00000000c8534ba4, 0x00000000f5f59b6f,
   0x000000007906ce14, 0x0000000044a01edf, 0x00000000024b6f82, 0x000000003fedbf49,
   0x000000008f9d8d38, 0x00000000b23b5df3, 0x00000000f4d02cae, 0x00000000c976fc65,
   0x0000000091dc3ebd, 0x00000000ac7aee76, 0x00000000ea919f2b, 0x00000000d7374fe0,
   0x0000000067477d91, 0x000000005ae1ad5a, 0x000000001c0adc07, 0x0000000021ac0ccc,
   0x000000005f52c59f, 0x0000000062f41554, 0x00000000241f6409, 0x0000000019b9b4c2,
   0x00000000a9c986b3, 0x00000000946f5678, 0x00000000d2842725, 0x00000000ef22f7ee,
   0x00000000b7883536, 0x000000008a2ee5fd, 0x00000000ccc594a0, 0x00000000f163446b,
   0x000000004113761a, 0x000000007cb5a6d1, 0x000000003a5ed78c, 0x0000000007f80747,
   0x000000008b0b523c, 0x00000000b6ad82f7, 0x00000000f046f3aa, 0x00000000cde02361,
   0x000000007d901110, 0x000000004036c1db, 0x0000000006ddb086, 0x000000003b7b604d,
   0x0000000063d1a295, 0x000000005e77725e, 0x00000000189c0303, 0x00000000253ad3c8,
   0x00000000954ae1b9, 0x00000000a8ec3172, 0x00000000ee07402f, 0x00000000d3a190e4,
   0x00000000f20d9c28, 0x00000000cfab4ce3, 0x0000000089403dbe, 0x00000000b4e6ed75,
   0x000000000496df04, 0x0000000039300fcf, 0x000000007fdb7e92, 0x00000000427dae59,
   0x000000001ad76c81, 0x000000002771bc4a, 0x00000000619acd17, 0x000000005c3c1ddc,
   0x00000000ec4c2fad, 0x00000000d1eaff66, 0x0000000097018e3b, 0x00000000aaa75ef0,
   0x0000000026540b8b, 0x000000001bf2db40, 0x000000005d19aa1d, 0x0000000060bf7ad6,
   0x00000000d0cf48a7, 0x00000000ed69986c, 0x00000000ab82e931, 0x00000000962439fa,
   0x00000000ce8efb22, 0x00000000f3282be9, 0x00000000b5c35ab4, 0x0000000088658a7f,
   0x000000003815b80e, 0x0000000005b368c5, 0x0000000043581998, 0x000000007efec953,
   0x00000000bea58b3e, 0x0000000083035bf5, 0x00000000c5e82aa8, 0x00000000f84efa63,
   0x00000000483ec812, 0x00000000759818d9, 0x0000000033736984, 0x000000000ed5b94f,
   0x00000000567f7b97, 0x000000006bd9ab5c, 0x000000002d32da01, 0x0000000010940aca,
   0x00000000a0e438bb, 0x000000009d42e870, 0x00000000dba9992d, 0x00000000e60f49e6,
   0x000000006afc1c9d, 0x00000000575acc56, 0x0000000011b1bd0b, 0x000000002c176dc0,
   0x000000009c675fb1, 0x00000000a1c18f7a, 0x00000000e72afe27, 0x00000000da8c2eec,
   0x000000008226ec34, 0x00000000bf803cff, 0x00000000f96b4da2, 0x00000000c4cd9d69,
   0x0000000074bdaf18, 0x00000000491b7fd3, 0x000000000ff00e8e, 0x000000003256de45,
   0x0000000013fad289, 0x000000002e5c0242, 0x0000000068b7731f, 0x000000005511a3d4,
   0x00000000e56191a5, 0x00000000d8c7416e, 0x000000009e2c3033, 0x00000000a38ae0f8,
   0x00000000fb202220, 0x00000000c686f2eb, 0x00000000806d83b6, 0x00000000bdcb537d,
   0x000000000dbb610c, 0x00000000301db1c7, 0x0000000076f6c09a, 0x000000004b501051,
   0x00000000c7a3452a, 0x00000000fa0595e1, 0x00000000bceee4bc, 0x0000000081483477,
   0x0000000031380606, 0x000000000c9ed6cd, 0x000000004a75a790, 0x0000000077d3775b,
   0x000000002f79b583, 0x0000000012df6548, 0x0000000054341415, 0x000000006992c4de,
   0x00000000d9e2f6af, 0x00000000e4442664, 0x00000000a2af5739, 0x000000009f0987f2,
   0x00000000e1f74ea1, 0x00000000dc519e6a, 0x000000009abaef37, 0x00000000a71c3ffc,
   0x00000000176c0d8d, 0x000000002acadd46, 0x000000006c21ac1b, 0x0000000051877cd0,
   0x00000000092dbe08, 0x00000000348b6ec3, 0x0000000072601f9e, 0x000000004fc6cf55,
   0x00000000ffb6fd24, 0x00000000c2102def, 0x0000000084fb5cb2, 0x00000000b95d8c79,
   0x0000000035aed902, 0x00000000080809c9, 0x000000004ee37894, 0x000000007345a85f,
   0x00000000c3359a2e, 0x00000000fe934ae5, 0x00000000b8783bb8, 0x0000000085deeb73,
   0x00000000dd7429ab, 0x00000000e0d2f960, 0x00000000a639883d, 0x000000009b9f58f6,
   0x000000002bef6a87, 0x000000001649ba4c, 0x0000000050a2cb11, 0x000000006d041bda,
   0x000000004ca81716, 0x00000000710ec7dd, 0x0000000037e5b680, 0x000000000a43664b,
   0x00000000ba33543a, 0x00000000879584f1, 0x00000000c17ef5ac, 0x00000000fcd82567,
   0x00000000a472e7bf, 0x0000000099d43774, 0x00000000df3f4629, 0x00000000e29996e2,
   0x0000000052e9a493, 0x000000006f4f7458, 0x0000000029a40505, 0x000000001402d5ce,
   0x0000000098f180b5, 0x00000000a557507e, 0x00000000e3bc2123, 0x00000000de1af1e8,
   0x000000006e6ac399, 0x0000000053cc1352, 0x000000001527620f, 0x000000002881b2c4,
   0x00000000702b701c, 0x000000004d8da0d7, 0x000000000b66d18a, 0x0000000036c00141,
   0x0000000086b03330, 0x00000000bb16e3fb, 0x00000000fdfd92a6, 0x00000000c05b426d,

  };


/* ---------------------------------- Tables for Crc64 ----------------------------------- */
/*                                    ----------------                                     */

//
// Generating polynomial for Crc64 is
// 0x9a6c9329ac4bc9b5 =
//                      x^64 + x^63 + x^61 + x^59 + x^58 + x^56 + x^55 + x^52 + x^49 + x^48 + x^47 +
//                           + x^46 + x^44 + x^41 + x^37 + x^36 + x^34 + x^32 + x^31 + x^28 + x^26 +
//                           + x^23 + x^22 + x^19 + x^16 + x^13 + x^12 + x^10 + x^9  + x^6  + x^4  +
//                           + x^3  + x^0
//

UInt64
CsCrc64Mult[64] =
{
   0x0080000000000000, 0x0000800000000000, 0x0000000080000000, 0x9a6c9329ac4bc9b5,
   0x10f4bb0f129310d6, 0x70f05dcea2ebd226, 0x311211205672822d, 0x2fc297db0f46c96e,
   0xca4d536fabf7da84, 0xfb4cdc3b379ee6ed, 0xea261148df25140a, 0x59ccb2c07aa6c9b4,
   0x20b3674a839af27a, 0x2d8e1986da94d583, 0x42cdf4c20337635d, 0x1d78724bf0f26839,
   0xb96c84e0afb34bd5, 0x5d2e1fcd2df0a3ea, 0xcd9506572332be42, 0x23bda2427f7d690f,
   0x347a953232374f07, 0x1c2a807ac2a8ceea, 0x9b92ad0e14fe1460, 0x2574114889f670b2,
   0x4a84a6c45e3bf520, 0x915bbac21cd1c7ff, 0xb0290ec579f291f5, 0xcf2548505c624e6e,
   0xb154f27bf08a8207, 0xce4e92344baf7d35, 0x51da8d7e057c5eb3, 0x9fb10823f5be15df,
   0x73b825b3ff1f71cf, 0x5db436c5406ebb74, 0xfa7ed8f3ec3f2bca, 0xc4d58efdc61b9ef6,
   0xa7e39e61e855bd45, 0x97ad46f9dd1bf2f1, 0x1a0abb01f853ee6b, 0x3f0827c3348f8215,
   0x4eb68c4506134607, 0x4a46f6de5df34e0a, 0x2d855d6a1c57a8dd, 0x8688da58e1115812,
   0x5232f417fc7c7300, 0xa4080fb2e767d8da, 0xd515a7e17693e562, 0x1181f7c862e94226,
   0x9e23cd058204ca91, 0x9b8992c57a0aed82, 0xb2c0afb84609b6ff, 0x2f7160553a5ea018,
   0x3cd378b5c99f2722, 0x814054ad61a3b058, 0xbf766189fce806d8, 0x85a5e898ac49f86f,
   0x34830d11bc84f346, 0x9644d95b173c8c1c, 0x150401ac9ac759b1, 0xebe1f7f46fb00eba,
   0x8ee4ce0c2e2bd662, 0x4000000000000000, 0x2000000000000000, 0x0800000000000000,
  };

static UInt64 CsCrc64Map1[256] =
{
   0x0000000000000000, 0x7f6ef0c830358979, 0xfedde190606b12f2, 0x81b31158505e9b8b,
   0xc962e5739841b68f, 0xb60c15bba8743ff6, 0x37bf04e3f82aa47d, 0x48d1f42bc81f2d04,
   0xa61cecb46814fe75, 0xd9721c7c5821770c, 0x58c10d24087fec87, 0x27affdec384a65fe,
   0x6f7e09c7f05548fa, 0x1010f90fc060c183, 0x91a3e857903e5a08, 0xeecd189fa00bd371,
   0x78e0ff3b88be6f81, 0x078e0ff3b88be6f8, 0x863d1eabe8d57d73, 0xf953ee63d8e0f40a,
   0xb1821a4810ffd90e, 0xceecea8020ca5077, 0x4f5ffbd87094cbfc, 0x30310b1040a14285,
   0xdefc138fe0aa91f4, 0xa192e347d09f188d, 0x2021f21f80c18306, 0x5f4f02d7b0f40a7f,
   0x179ef6fc78eb277b, 0x68f0063448deae02, 0xe943176c18803589, 0x962de7a428b5bcf0,
   0xf1c1fe77117cdf02, 0x8eaf0ebf2149567b, 0x0f1c1fe77117cdf0, 0x7072ef2f41224489,
   0x38a31b04893d698d, 0x47cdebccb908e0f4, 0xc67efa94e9567b7f, 0xb9100a5cd963f206,
   0x57dd12c379682177, 0x28b3e20b495da80e, 0xa900f35319033385, 0xd66e039b2936bafc,
   0x9ebff7b0e12997f8, 0xe1d10778d11c1e81, 0x606216208142850a, 0x1f0ce6e8b1770c73,
   0x8921014c99c2b083, 0xf64ff184a9f739fa, 0x77fce0dcf9a9a271, 0x08921014c99c2b08,
   0x4043e43f0183060c, 0x3f2d14f731b68f75, 0xbe9e05af61e814fe, 0xc1f0f56751dd9d87,
   0x2f3dedf8f1d64ef6, 0x50531d30c1e3c78f, 0xd1e00c6891bd5c04, 0xae8efca0a188d57d,
   0xe65f088b6997f879, 0x9931f84359a27100, 0x1882e91b09fcea8b, 0x67ec19d339c963f2,
   0xd75adabd7a6e2d6f, 0xa8342a754a5ba416, 0x29873b2d1a053f9d, 0x56e9cbe52a30b6e4,
   0x1e383fcee22f9be0, 0x6156cf06d21a1299, 0xe0e5de5e82448912, 0x9f8b2e96b271006b,
   0x71463609127ad31a, 0x0e28c6c1224f5a63, 0x8f9bd7997211c1e8, 0xf0f5275142244891,
   0xb824d37a8a3b6595, 0xc74a23b2ba0eecec, 0x46f932eaea507767, 0x3997c222da65fe1e,
   0xafba2586f2d042ee, 0xd0d4d54ec2e5cb97, 0x5167c41692bb501c, 0x2e0934dea28ed965,
   0x66d8c0f56a91f461, 0x19b6303d5aa47d18, 0x980521650afae693, 0xe76bd1ad3acf6fea,
   0x09a6c9329ac4bc9b, 0x76c839faaaf135e2, 0xf77b28a2faafae69, 0x8815d86aca9a2710,
   0xc0c42c4102850a14, 0xbfaadc8932b0836d, 0x3e19cdd162ee18e6, 0x41773d1952db919f,
   0x269b24ca6b12f26d, 0x59f5d4025b277b14, 0xd846c55a0b79e09f, 0xa72835923b4c69e6,
   0xeff9c1b9f35344e2, 0x90973171c366cd9b, 0x1124202993385610, 0x6e4ad0e1a30ddf69,
   0x8087c87e03060c18, 0xffe938b633338561, 0x7e5a29ee636d1eea, 0x0134d92653589793,
   0x49e52d0d9b47ba97, 0x368bddc5ab7233ee, 0xb738cc9dfb2ca865, 0xc8563c55cb19211c,
   0x5e7bdbf1e3ac9dec, 0x21152b39d3991495, 0xa0a63a6183c78f1e, 0xdfc8caa9b3f20667,
   0x97193e827bed2b63, 0xe877ce4a4bd8a21a, 0x69c4df121b863991, 0x16aa2fda2bb3b0e8,
   0xf86737458bb86399, 0x8709c78dbb8deae0, 0x06bad6d5ebd3716b, 0x79d4261ddbe6f812,
   0x3105d23613f9d516, 0x4e6b22fe23cc5c6f, 0xcfd833a67392c7e4, 0xb0b6c36e43a74e9d,
   0x9a6c9329ac4bc9b5, 0xe50263e19c7e40cc, 0x64b172b9cc20db47, 0x1bdf8271fc15523e,
   0x530e765a340a7f3a, 0x2c608692043ff643, 0xadd397ca54616dc8, 0xd2bd67026454e4b1,
   0x3c707f9dc45f37c0, 0x431e8f55f46abeb9, 0xc2ad9e0da4342532, 0xbdc36ec59401ac4b,
   0xf5129aee5c1e814f, 0x8a7c6a266c2b0836, 0x0bcf7b7e3c7593bd, 0x74a18bb60c401ac4,
   0xe28c6c1224f5a634, 0x9de29cda14c02f4d, 0x1c518d82449eb4c6, 0x633f7d4a74ab3dbf,
   0x2bee8961bcb410bb, 0x548079a98c8199c2, 0xd53368f1dcdf0249, 0xaa5d9839ecea8b30,
   0x449080a64ce15841, 0x3bfe706e7cd4d138, 0xba4d61362c8a4ab3, 0xc52391fe1cbfc3ca,
   0x8df265d5d4a0eece, 0xf29c951de49567b7, 0x732f8445b4cbfc3c, 0x0c41748d84fe7545,
   0x6bad6d5ebd3716b7, 0x14c39d968d029fce, 0x95708ccedd5c0445, 0xea1e7c06ed698d3c,
   0xa2cf882d2576a038, 0xdda178e515432941, 0x5c1269bd451db2ca, 0x237c997575283bb3,
   0xcdb181ead523e8c2, 0xb2df7122e51661bb, 0x336c607ab548fa30, 0x4c0290b2857d7349,
   0x04d364994d625e4d, 0x7bbd94517d57d734, 0xfa0e85092d094cbf, 0x856075c11d3cc5c6,
   0x134d926535897936, 0x6c2362ad05bcf04f, 0xed9073f555e26bc4, 0x92fe833d65d7e2bd,
   0xda2f7716adc8cfb9, 0xa54187de9dfd46c0, 0x24f29686cda3dd4b, 0x5b9c664efd965432,
   0xb5517ed15d9d8743, 0xca3f8e196da80e3a, 0x4b8c9f413df695b1, 0x34e26f890dc31cc8,
   0x7c339ba2c5dc31cc, 0x035d6b6af5e9b8b5, 0x82ee7a32a5b7233e, 0xfd808afa9582aa47,
   0x4d364994d625e4da, 0x3258b95ce6106da3, 0xb3eba804b64ef628, 0xcc8558cc867b7f51,
   0x8454ace74e645255, 0xfb3a5c2f7e51db2c, 0x7a894d772e0f40a7, 0x05e7bdbf1e3ac9de,
   0xeb2aa520be311aaf, 0x944455e88e0493d6, 0x15f744b0de5a085d, 0x6a99b478ee6f8124,
   0x224840532670ac20, 0x5d26b09b16452559, 0xdc95a1c3461bbed2, 0xa3fb510b762e37ab,
   0x35d6b6af5e9b8b5b, 0x4ab846676eae0222, 0xcb0b573f3ef099a9, 0xb465a7f70ec510d0,
   0xfcb453dcc6da3dd4, 0x83daa314f6efb4ad, 0x0269b24ca6b12f26, 0x7d0742849684a65f,
   0x93ca5a1b368f752e, 0xeca4aad306bafc57, 0x6d17bb8b56e467dc, 0x12794b4366d1eea5,
   0x5aa8bf68aecec3a1, 0x25c64fa09efb4ad8, 0xa4755ef8cea5d153, 0xdb1bae30fe90582a,
   0xbcf7b7e3c7593bd8, 0xc399472bf76cb2a1, 0x422a5673a732292a, 0x3d44a6bb9707a053,
   0x759552905f188d57, 0x0afba2586f2d042e, 0x8b48b3003f739fa5, 0xf42643c80f4616dc,
   0x1aeb5b57af4dc5ad, 0x6585ab9f9f784cd4, 0xe436bac7cf26d75f, 0x9b584a0fff135e26,
   0xd389be24370c7322, 0xace74eec0739fa5b, 0x2d545fb4576761d0, 0x523aaf7c6752e8a9,
   0xc41748d84fe75459, 0xbb79b8107fd2dd20, 0x3acaa9482f8c46ab, 0x45a459801fb9cfd2,
   0x0d75adabd7a6e2d6, 0x721b5d63e7936baf, 0xf3a84c3bb7cdf024, 0x8cc6bcf387f8795d,
   0x620ba46c27f3aa2c, 0x1d6554a417c62355, 0x9cd645fc4798b8de, 0xe3b8b53477ad31a7,
   0xab69411fbfb21ca3, 0xd407b1d78f8795da, 0x55b4a08fdfd90e51, 0x2ada5047efec8728,
  };

static UInt64 CsCrc64Map32[2048] =
{
   0x0000000000000000, 0xb8c533c1177eb231, 0x455341d1766af709, 0xfd96721061144538,
   0x8aa683a2ecd5ee12, 0x3263b063fbab5c23, 0xcff5c2739abf191b, 0x7730f1b28dc1ab2a,
   0x21942116813c4f4f, 0x995112d79642fd7e, 0x64c760c7f756b846, 0xdc025306e0280a77,
   0xab32a2b46de9a15d, 0x13f791757a97136c, 0xee61e3651b835654, 0x56a4d0a40cfde465,
   0x4328422d02789e9e, 0xfbed71ec15062caf, 0x067b03fc74126997, 0xbebe303d636cdba6,
   0xc98ec18feead708c, 0x714bf24ef9d3c2bd, 0x8cdd805e98c78785, 0x3418b39f8fb935b4,
   0x62bc633b8344d1d1, 0xda7950fa943a63e0, 0x27ef22eaf52e26d8, 0x9f2a112be25094e9,
   0xe81ae0996f913fc3, 0x50dfd35878ef8df2, 0xad49a14819fbc8ca, 0x158c92890e857afb,
   0x8650845a04f13d3c, 0x3e95b79b138f8f0d, 0xc303c58b729bca35, 0x7bc6f64a65e57804,
   0x0cf607f8e824d32e, 0xb4333439ff5a611f, 0x49a546299e4e2427, 0xf16075e889309616,
   0xa7c4a54c85cd7273, 0x1f01968d92b3c042, 0xe297e49df3a7857a, 0x5a52d75ce4d9374b,
   0x2d6226ee69189c61, 0x95a7152f7e662e50, 0x6831673f1f726b68, 0xd0f454fe080cd959,
   0xc578c6770689a3a2, 0x7dbdf5b611f71193, 0x802b87a670e354ab, 0x38eeb467679de69a,
   0x4fde45d5ea5c4db0, 0xf71b7614fd22ff81, 0x0a8d04049c36bab9, 0xb24837c58b480888,
   0xe4ece76187b5eced, 0x5c29d4a090cb5edc, 0xa1bfa6b0f1df1be4, 0x197a9571e6a1a9d5,
   0x6e4a64c36b6002ff, 0xd68f57027c1eb0ce, 0x2b1925121d0af5f6, 0x93dc16d30a7447c7,
   0x38782ee75175e913, 0x80bd1d26460b5b22, 0x7d2b6f36271f1e1a, 0xc5ee5cf73061ac2b,
   0xb2dead45bda00701, 0x0a1b9e84aadeb530, 0xf78dec94cbcaf008, 0x4f48df55dcb44239,
   0x19ec0ff1d049a65c, 0xa1293c30c737146d, 0x5cbf4e20a6235155, 0xe47a7de1b15de364,
   0x934a8c533c9c484e, 0x2b8fbf922be2fa7f, 0xd619cd824af6bf47, 0x6edcfe435d880d76,
   0x7b506cca530d778d, 0xc3955f0b4473c5bc, 0x3e032d1b25678084, 0x86c61eda321932b5,
   0xf1f6ef68bfd8999f, 0x4933dca9a8a62bae, 0xb4a5aeb9c9b26e96, 0x0c609d78deccdca7,
   0x5ac44ddcd23138c2, 0xe2017e1dc54f8af3, 0x1f970c0da45bcfcb, 0xa7523fccb3257dfa,
   0xd062ce7e3ee4d6d0, 0x68a7fdbf299a64e1, 0x95318faf488e21d9, 0x2df4bc6e5ff093e8,
   0xbe28aabd5584d42f, 0x06ed997c42fa661e, 0xfb7beb6c23ee2326, 0x43bed8ad34909117,
   0x348e291fb9513a3d, 0x8c4b1adeae2f880c, 0x71dd68cecf3bcd34, 0xc9185b0fd8457f05,
   0x9fbc8babd4b89b60, 0x2779b86ac3c62951, 0xdaefca7aa2d26c69, 0x622af9bbb5acde58,
   0x151a0809386d7572, 0xaddf3bc82f13c743, 0x504949d84e07827b, 0xe88c7a195979304a,
   0xfd00e89057fc4ab1, 0x45c5db514082f880, 0xb853a9412196bdb8, 0x00969a8036e80f89,
   0x77a66b32bb29a4a3, 0xcf6358f3ac571692, 0x32f52ae3cd4353aa, 0x8a301922da3de19b,
   0xdc94c986d6c005fe, 0x6451fa47c1beb7cf, 0x99c78857a0aaf2f7, 0x2102bb96b7d440c6,
   0x56324a243a15ebec, 0xeef779e52d6b59dd, 0x13610bf54c7f1ce5, 0xaba438345b01aed4,
   0x70f05dcea2ebd226, 0xc8356e0fb5956017, 0x35a31c1fd481252f, 0x8d662fdec3ff971e,
   0xfa56de6c4e3e3c34, 0x4293edad59408e05, 0xbf059fbd3854cb3d, 0x07c0ac7c2f2a790c,
   0x51647cd823d79d69, 0xe9a14f1934a92f58, 0x14373d0955bd6a60, 0xacf20ec842c3d851,
   0xdbc2ff7acf02737b, 0x6307ccbbd87cc14a, 0x9e91beabb9688472, 0x26548d6aae163643,
   0x33d81fe3a0934cb8, 0x8b1d2c22b7edfe89, 0x768b5e32d6f9bbb1, 0xce4e6df3c1870980,
   0xb97e9c414c46a2aa, 0x01bbaf805b38109b, 0xfc2ddd903a2c55a3, 0x44e8ee512d52e792,
   0x124c3ef521af03f7, 0xaa890d3436d1b1c6, 0x571f7f2457c5f4fe, 0xefda4ce540bb46cf,
   0x98eabd57cd7aede5, 0x202f8e96da045fd4, 0xddb9fc86bb101aec, 0x657ccf47ac6ea8dd,
   0xf6a0d994a61aef1a, 0x4e65ea55b1645d2b, 0xb3f39845d0701813, 0x0b36ab84c70eaa22,
   0x7c065a364acf0108, 0xc4c369f75db1b339, 0x39551be73ca5f601, 0x819028262bdb4430,
   0xd734f8822726a055, 0x6ff1cb4330581264, 0x9267b953514c575c, 0x2aa28a924632e56d,
   0x5d927b20cbf34e47, 0xe55748e1dc8dfc76, 0x18c13af1bd99b94e, 0xa0040930aae70b7f,
   0xb5889bb9a4627184, 0x0d4da878b31cc3b5, 0xf0dbda68d208868d, 0x481ee9a9c57634bc,
   0x3f2e181b48b79f96, 0x87eb2bda5fc92da7, 0x7a7d59ca3edd689f, 0xc2b86a0b29a3daae,
   0x941cbaaf255e3ecb, 0x2cd9896e32208cfa, 0xd14ffb7e5334c9c2, 0x698ac8bf444a7bf3,
   0x1eba390dc98bd0d9, 0xa67f0accdef562e8, 0x5be978dcbfe127d0, 0xe32c4b1da89f95e1,
   0x48887329f39e3b35, 0xf04d40e8e4e08904, 0x0ddb32f885f4cc3c, 0xb51e0139928a7e0d,
   0xc22ef08b1f4bd527, 0x7aebc34a08356716, 0x877db15a6921222e, 0x3fb8829b7e5f901f,
   0x691c523f72a2747a, 0xd1d961fe65dcc64b, 0x2c4f13ee04c88373, 0x948a202f13b63142,
   0xe3bad19d9e779a68, 0x5b7fe25c89092859, 0xa6e9904ce81d6d61, 0x1e2ca38dff63df50,
   0x0ba03104f1e6a5ab, 0xb36502c5e698179a, 0x4ef370d5878c52a2, 0xf636431490f2e093,
   0x8106b2a61d334bb9, 0x39c381670a4df988, 0xc455f3776b59bcb0, 0x7c90c0b67c270e81,
   0x2a34101270daeae4, 0x92f123d367a458d5, 0x6f6751c306b01ded, 0xd7a2620211ceafdc,
   0xa09293b09c0f04f6, 0x1857a0718b71b6c7, 0xe5c1d261ea65f3ff, 0x5d04e1a0fd1b41ce,
   0xced8f773f76f0609, 0x761dc4b2e011b438, 0x8b8bb6a28105f100, 0x334e8563967b4331,
   0x447e74d11bbae81b, 0xfcbb47100cc45a2a, 0x012d35006dd01f12, 0xb9e806c17aaead23,
   0xef4cd66576534946, 0x5789e5a4612dfb77, 0xaa1f97b40039be4f, 0x12daa47517470c7e,
   0x65ea55c79a86a754, 0xdd2f66068df81565, 0x20b91416ecec505d, 0x987c27d7fb92e26c,
   0x8df0b55ef5179897, 0x3535869fe2692aa6, 0xc8a3f48f837d6f9e, 0x7066c74e9403ddaf,
   0x075636fc19c27685, 0xbf93053d0ebcc4b4, 0x4205772d6fa8818c, 0xfac044ec78d633bd,
   0xac649448742bd7d8, 0x14a1a789635565e9, 0xe937d599024120d1, 0x51f2e658153f92e0,
   0x26c217ea98fe39ca, 0x9e07242b8f808bfb, 0x6391563bee94cec3, 0xdb5465faf9ea7cf2,

   0x0000000000000000, 0xf6f734b768e04748, 0xd9374f3d89571dfb, 0x2fc07b8ae1b75ab3,
   0x86b7b8284a39a89d, 0x70408c9f22d9efd5, 0x5f80f715c36eb566, 0xa977c3a2ab8ef22e,
   0x39b65603cce4c251, 0xcf4162b4a4048519, 0xe081193e45b3dfaa, 0x16762d892d5398e2,
   0xbf01ee2b86dd6acc, 0x49f6da9cee3d2d84, 0x6636a1160f8a7737, 0x90c195a1676a307f,
   0x736cac0799c984a2, 0x859b98b0f129c3ea, 0xaa5be33a109e9959, 0x5cacd78d787ede11,
   0xf5db142fd3f02c3f, 0x032c2098bb106b77, 0x2cec5b125aa731c4, 0xda1b6fa53247768c,
   0x4adafa04552d46f3, 0xbc2dceb33dcd01bb, 0x93edb539dc7a5b08, 0x651a818eb49a1c40,
   0xcc6d422c1f14ee6e, 0x3a9a769b77f4a926, 0x155a0d119643f395, 0xe3ad39a6fea3b4dd,
   0xe6d9580f33930944, 0x102e6cb85b734e0c, 0x3fee1732bac414bf, 0xc9192385d22453f7,
   0x606ee02779aaa1d9, 0x9699d490114ae691, 0xb959af1af0fdbc22, 0x4fae9bad981dfb6a,
   0xdf6f0e0cff77cb15, 0x29983abb97978c5d, 0x065841317620d6ee, 0xf0af75861ec091a6,
   0x59d8b624b54e6388, 0xaf2f8293ddae24c0, 0x80eff9193c197e73, 0x7618cdae54f9393b,
   0x95b5f408aa5a8de6, 0x6342c0bfc2bacaae, 0x4c82bb35230d901d, 0xba758f824bedd755,
   0x13024c20e063257b, 0xe5f5789788836233, 0xca35031d69343880, 0x3cc237aa01d47fc8,
   0xac03a20b66be4fb7, 0x5af496bc0e5e08ff, 0x7534ed36efe9524c, 0x83c3d98187091504,
   0x2ab41a232c87e72a, 0xdc432e944467a062, 0xf383551ea5d0fad1, 0x057461a9cd30bd99,
   0xf96b964d3fb181e3, 0x0f9ca2fa5751c6ab, 0x205cd970b6e69c18, 0xd6abedc7de06db50,
   0x7fdc2e657588297e, 0x892b1ad21d686e36, 0xa6eb6158fcdf3485, 0x501c55ef943f73cd,
   0xc0ddc04ef35543b2, 0x362af4f99bb504fa, 0x19ea8f737a025e49, 0xef1dbbc412e21901,
   0x466a7866b96ceb2f, 0xb09d4cd1d18cac67, 0x9f5d375b303bf6d4, 0x69aa03ec58dbb19c,
   0x8a073a4aa6780541, 0x7cf00efdce984209, 0x533075772f2f18ba, 0xa5c741c047cf5ff2,
   0x0cb08262ec41addc, 0xfa47b6d584a1ea94, 0xd587cd5f6516b027, 0x2370f9e80df6f76f,
   0xb3b16c496a9cc710, 0x454658fe027c8058, 0x6a862374e3cbdaeb, 0x9c7117c38b2b9da3,
   0x3506d46120a56f8d, 0xc3f1e0d6484528c5, 0xec319b5ca9f27276, 0x1ac6afebc112353e,
   0x1fb2ce420c2288a7, 0xe945faf564c2cfef, 0xc685817f8575955c, 0x3072b5c8ed95d214,
   0x9905766a461b203a, 0x6ff242dd2efb6772, 0x40323957cf4c3dc1, 0xb6c50de0a7ac7a89,
   0x26049841c0c64af6, 0xd0f3acf6a8260dbe, 0xff33d77c4991570d, 0x09c4e3cb21711045,
   0xa0b320698affe26b, 0x564414dee21fa523, 0x79846f5403a8ff90, 0x8f735be36b48b8d8,
   0x6cde624595eb0c05, 0x9a2956f2fd0b4b4d, 0xb5e92d781cbc11fe, 0x431e19cf745c56b6,
   0xea69da6ddfd2a498, 0x1c9eeedab732e3d0, 0x335e95505685b963, 0xc5a9a1e73e65fe2b,
   0x55683446590fce54, 0xa39f00f131ef891c, 0x8c5f7b7bd058d3af, 0x7aa84fccb8b894e7,
   0xd3df8c6e133666c9, 0x2528b8d97bd62181, 0x0ae8c3539a617b32, 0xfc1ff7e4f2813c7a,
   0xc60e0ac927f490ad, 0x30f93e7e4f14d7e5, 0x1f3945f4aea38d56, 0xe9ce7143c643ca1e,
   0x40b9b2e16dcd3830, 0xb64e8656052d7f78, 0x998efddce49a25cb, 0x6f79c96b8c7a6283,
   0xffb85ccaeb1052fc, 0x094f687d83f015b4, 0x268f13f762474f07, 0xd07827400aa7084f,
   0x790fe4e2a129fa61, 0x8ff8d055c9c9bd29, 0xa038abdf287ee79a, 0x56cf9f68409ea0d2,
   0xb562a6cebe3d140f, 0x43959279d6dd5347, 0x6c55e9f3376a09f4, 0x9aa2dd445f8a4ebc,
   0x33d51ee6f404bc92, 0xc5222a519ce4fbda, 0xeae251db7d53a169, 0x1c15656c15b3e621,
   0x8cd4f0cd72d9d65e, 0x7a23c47a1a399116, 0x55e3bff0fb8ecba5, 0xa3148b47936e8ced,
   0x0a6348e538e07ec3, 0xfc947c525000398b, 0xd35407d8b1b76338, 0x25a3336fd9572470,
   0x20d752c6146799e9, 0xd62066717c87dea1, 0xf9e01dfb9d308412, 0x0f17294cf5d0c35a,
   0xa660eaee5e5e3174, 0x5097de5936be763c, 0x7f57a5d3d7092c8f, 0x89a09164bfe96bc7,
   0x196104c5d8835bb8, 0xef963072b0631cf0, 0xc0564bf851d44643, 0x36a17f4f3934010b,
   0x9fd6bced92baf325, 0x6921885afa5ab46d, 0x46e1f3d01bedeede, 0xb016c767730da996,
   0x53bbfec18dae1d4b, 0xa54cca76e54e5a03, 0x8a8cb1fc04f900b0, 0x7c7b854b6c1947f8,
   0xd50c46e9c797b5d6, 0x23fb725eaf77f29e, 0x0c3b09d44ec0a82d, 0xfacc3d632620ef65,
   0x6a0da8c2414adf1a, 0x9cfa9c7529aa9852, 0xb33ae7ffc81dc2e1, 0x45cdd348a0fd85a9,
   0xecba10ea0b737787, 0x1a4d245d639330cf, 0x358d5fd782246a7c, 0xc37a6b60eac42d34,
   0x3f659c841845114e, 0xc992a83370a55606, 0xe652d3b991120cb5, 0x10a5e70ef9f24bfd,
   0xb9d224ac527cb9d3, 0x4f25101b3a9cfe9b, 0x60e56b91db2ba428, 0x96125f26b3cbe360,
   0x06d3ca87d4a1d31f, 0xf024fe30bc419457, 0xdfe485ba5df6cee4, 0x2913b10d351689ac,
   0x806472af9e987b82, 0x76934618f6783cca, 0x59533d9217cf6679, 0xafa409257f2f2131,
   0x4c093083818c95ec, 0xbafe0434e96cd2a4, 0x953e7fbe08db8817, 0x63c94b09603bcf5f,
   0xcabe88abcbb53d71, 0x3c49bc1ca3557a39, 0x1389c79642e2208a, 0xe57ef3212a0267c2,
   0x75bf66804d6857bd, 0x83485237258810f5, 0xac8829bdc43f4a46, 0x5a7f1d0aacdf0d0e,
   0xf308dea80751ff20, 0x05ffea1f6fb1b868, 0x2a3f91958e06e2db, 0xdcc8a522e6e6a593,
   0xd9bcc48b2bd6180a, 0x2f4bf03c43365f42, 0x008b8bb6a28105f1, 0xf67cbf01ca6142b9,
   0x5f0b7ca361efb097, 0xa9fc4814090ff7df, 0x863c339ee8b8ad6c, 0x70cb07298058ea24,
   0xe00a9288e732da5b, 0x16fda63f8fd29d13, 0x393dddb56e65c7a0, 0xcfcae902068580e8,
   0x66bd2aa0ad0b72c6, 0x904a1e17c5eb358e, 0xbf8a659d245c6f3d, 0x497d512a4cbc2875,
   0xaad0688cb21f9ca8, 0x5c275c3bdaffdbe0, 0x73e727b13b488153, 0x8510130653a8c61b,
   0x2c67d0a4f8263435, 0xda90e41390c6737d, 0xf5509f99717129ce, 0x03a7ab2e19916e86,
   0x93663e8f7efb5ef9, 0x65910a38161b19b1, 0x4a5171b2f7ac4302, 0xbca645059f4c044a,
   0x15d186a734c2f664, 0xe326b2105c22b12c, 0xcce6c99abd95eb9f, 0x3a11fd2dd575acd7,

   0x0000000000000000, 0x71b0c13da512335d, 0xe361827b4a2466ba, 0x92d14346ef3655e7,
   0xf21a22a5ccdf5e1f, 0x83aae39869cd6d42, 0x117ba0de86fb38a5, 0x60cb61e323e90bf8,
   0xd0ed6318c1292f55, 0xa15da225643b1c08, 0x338ce1638b0d49ef, 0x423c205e2e1f7ab2,
   0x22f741bd0df6714a, 0x53478080a8e44217, 0xc196c3c647d217f0, 0xb02602fbe2c024ad,
   0x9503e062dac5cdc1, 0xe4b3215f7fd7fe9c, 0x7662621990e1ab7b, 0x07d2a32435f39826,
   0x6719c2c7161a93de, 0x16a903fab308a083, 0x847840bc5c3ef564, 0xf5c88181f92cc639,
   0x45ee837a1bece294, 0x345e4247befed1c9, 0xa68f010151c8842e, 0xd73fc03cf4dab773,
   0xb7f4a1dfd733bc8b, 0xc64460e272218fd6, 0x549523a49d17da31, 0x2525e2993805e96c,
   0x1edee696ed1c08e9, 0x6f6e27ab480e3bb4, 0xfdbf64eda7386e53, 0x8c0fa5d0022a5d0e,
   0xecc4c43321c356f6, 0x9d74050e84d165ab, 0x0fa546486be7304c, 0x7e158775cef50311,
   0xce33858e2c3527bc, 0xbf8344b3892714e1, 0x2d5207f566114106, 0x5ce2c6c8c303725b,
   0x3c29a72be0ea79a3, 0x4d99661645f84afe, 0xdf482550aace1f19, 0xaef8e46d0fdc2c44,
   0x8bdd06f437d9c528, 0xfa6dc7c992cbf675, 0x68bc848f7dfda392, 0x190c45b2d8ef90cf,
   0x79c72451fb069b37, 0x0877e56c5e14a86a, 0x9aa6a62ab122fd8d, 0xeb1667171430ced0,
   0x5b3065ecf6f0ea7d, 0x2a80a4d153e2d920, 0xb851e797bcd48cc7, 0xc9e126aa19c6bf9a,
   0xa92a47493a2fb462, 0xd89a86749f3d873f, 0x4a4bc532700bd2d8, 0x3bfb040fd519e185,
   0x3dbdcd2dda3811d2, 0x4c0d0c107f2a228f, 0xdedc4f56901c7768, 0xaf6c8e6b350e4435,
   0xcfa7ef8816e74fcd, 0xbe172eb5b3f57c90, 0x2cc66df35cc32977, 0x5d76accef9d11a2a,
   0xed50ae351b113e87, 0x9ce06f08be030dda, 0x0e312c4e5135583d, 0x7f81ed73f4276b60,
   0x1f4a8c90d7ce6098, 0x6efa4dad72dc53c5, 0xfc2b0eeb9dea0622, 0x8d9bcfd638f8357f,
   0xa8be2d4f00fddc13, 0xd90eec72a5efef4e, 0x4bdfaf344ad9baa9, 0x3a6f6e09efcb89f4,
   0x5aa40feacc22820c, 0x2b14ced76930b151, 0xb9c58d918606e4b6, 0xc8754cac2314d7eb,
   0x78534e57c1d4f346, 0x09e38f6a64c6c01b, 0x9b32cc2c8bf095fc, 0xea820d112ee2a6a1,
   0x8a496cf20d0bad59, 0xfbf9adcfa8199e04, 0x6928ee89472fcbe3, 0x18982fb4e23df8be,
   0x23632bbb3724193b, 0x52d3ea8692362a66, 0xc002a9c07d007f81, 0xb1b268fdd8124cdc,
   0xd179091efbfb4724, 0xa0c9c8235ee97479, 0x32188b65b1df219e, 0x43a84a5814cd12c3,
   0xf38e48a3f60d366e, 0x823e899e531f0533, 0x10efcad8bc2950d4, 0x615f0be5193b6389,
   0x01946a063ad26871, 0x7024ab3b9fc05b2c, 0xe2f5e87d70f60ecb, 0x93452940d5e43d96,
   0xb660cbd9ede1d4fa, 0xc7d00ae448f3e7a7, 0x550149a2a7c5b240, 0x24b1889f02d7811d,
   0x447ae97c213e8ae5, 0x35ca2841842cb9b8, 0xa71b6b076b1aec5f, 0xd6abaa3ace08df02,
   0x668da8c12cc8fbaf, 0x173d69fc89dac8f2, 0x85ec2aba66ec9d15, 0xf45ceb87c3feae48,
   0x94978a64e017a5b0, 0xe5274b59450596ed, 0x77f6081faa33c30a, 0x0646c9220f21f057,
   0x7b7b9a5bb47023a4, 0x0acb5b66116210f9, 0x981a1820fe54451e, 0xe9aad91d5b467643,
   0x8961b8fe78af7dbb, 0xf8d179c3ddbd4ee6, 0x6a003a85328b1b01, 0x1bb0fbb89799285c,
   0xab96f94375590cf1, 0xda26387ed04b3fac, 0x48f77b383f7d6a4b, 0x3947ba059a6f5916,
   0x598cdbe6b98652ee, 0x283c1adb1c9461b3, 0xbaed599df3a23454, 0xcb5d98a056b00709,
   0xee787a396eb5ee65, 0x9fc8bb04cba7dd38, 0x0d19f842249188df, 0x7ca9397f8183bb82,
   0x1c62589ca26ab07a, 0x6dd299a107788327, 0xff03dae7e84ed6c0, 0x8eb31bda4d5ce59d,
   0x3e951921af9cc130, 0x4f25d81c0a8ef26d, 0xddf49b5ae5b8a78a, 0xac445a6740aa94d7,
   0xcc8f3b8463439f2f, 0xbd3ffab9c651ac72, 0x2feeb9ff2967f995, 0x5e5e78c28c75cac8,
   0x65a57ccd596c2b4d, 0x1415bdf0fc7e1810, 0x86c4feb613484df7, 0xf7743f8bb65a7eaa,
   0x97bf5e6895b37552, 0xe60f9f5530a1460f, 0x74dedc13df9713e8, 0x056e1d2e7a8520b5,
   0xb5481fd598450418, 0xc4f8dee83d573745, 0x56299daed26162a2, 0x27995c93777351ff,
   0x47523d70549a5a07, 0x36e2fc4df188695a, 0xa433bf0b1ebe3cbd, 0xd5837e36bbac0fe0,
   0xf0a69caf83a9e68c, 0x81165d9226bbd5d1, 0x13c71ed4c98d8036, 0x6277dfe96c9fb36b,
   0x02bcbe0a4f76b893, 0x730c7f37ea648bce, 0xe1dd3c710552de29, 0x906dfd4ca040ed74,
   0x204bffb74280c9d9, 0x51fb3e8ae792fa84, 0xc32a7dcc08a4af63, 0xb29abcf1adb69c3e,
   0xd251dd128e5f97c6, 0xa3e11c2f2b4da49b, 0x31305f69c47bf17c, 0x40809e546169c221,
   0x46c657766e483276, 0x3776964bcb5a012b, 0xa5a7d50d246c54cc, 0xd4171430817e6791,
   0xb4dc75d3a2976c69, 0xc56cb4ee07855f34, 0x57bdf7a8e8b30ad3, 0x260d36954da1398e,
   0x962b346eaf611d23, 0xe79bf5530a732e7e, 0x754ab615e5457b99, 0x04fa7728405748c4,
   0x643116cb63be433c, 0x1581d7f6c6ac7061, 0x875094b0299a2586, 0xf6e0558d8c8816db,
   0xd3c5b714b48dffb7, 0xa2757629119fccea, 0x30a4356ffea9990d, 0x4114f4525bbbaa50,
   0x21df95b17852a1a8, 0x506f548cdd4092f5, 0xc2be17ca3276c712, 0xb30ed6f79764f44f,
   0x0328d40c75a4d0e2, 0x72981531d0b6e3bf, 0xe04956773f80b658, 0x91f9974a9a928505,
   0xf132f6a9b97b8efd, 0x808237941c69bda0, 0x125374d2f35fe847, 0x63e3b5ef564ddb1a,
   0x5818b1e083543a9f, 0x29a870dd264609c2, 0xbb79339bc9705c25, 0xcac9f2a66c626f78,
   0xaa0293454f8b6480, 0xdbb25278ea9957dd, 0x4963113e05af023a, 0x38d3d003a0bd3167,
   0x88f5d2f8427d15ca, 0xf94513c5e76f2697, 0x6b94508308597370, 0x1a2491bead4b402d,
   0x7aeff05d8ea24bd5, 0x0b5f31602bb07888, 0x998e7226c4862d6f, 0xe83eb31b61941e32,
   0xcd1b51825991f75e, 0xbcab90bffc83c403, 0x2e7ad3f913b591e4, 0x5fca12c4b6a7a2b9,
   0x3f017327954ea941, 0x4eb1b21a305c9a1c, 0xdc60f15cdf6acffb, 0xadd030617a78fca6,
   0x1df6329a98b8d80b, 0x6c46f3a73daaeb56, 0xfe97b0e1d29cbeb1, 0x8f2771dc778e8dec,
   0xefec103f54678614, 0x9e5cd102f175b549, 0x0c8d92441e43e0ae, 0x7d3d5379bb51d3f3,

   0x0000000000000000, 0xbfdb6c480f15915e, 0x4b6ffec346bcb1d7, 0xf4b4928b49a92089,
   0x96dffd868d7963ae, 0x290491ce826cf2f0, 0xddb00345cbc5d279, 0x626b6f0dc4d04327,
   0x1966dd5e42655437, 0xa6bdb1164d70c569, 0x5209239d04d9e5e0, 0xedd24fd50bcc74be,
   0x8fb920d8cf1c3799, 0x30624c90c009a6c7, 0xc4d6de1b89a0864e, 0x7b0db25386b51710,
   0x32cdbabc84caa86e, 0x8d16d6f48bdf3930, 0x79a2447fc27619b9, 0xc6792837cd6388e7,
   0xa412473a09b3cbc0, 0x1bc92b7206a65a9e, 0xef7db9f94f0f7a17, 0x50a6d5b1401aeb49,
   0x2bab67e2c6affc59, 0x94700baac9ba6d07, 0x60c4992180134d8e, 0xdf1ff5698f06dcd0,
   0xbd749a644bd69ff7, 0x02aff62c44c30ea9, 0xf61b64a70d6a2e20, 0x49c008ef027fbf7e,
   0x659b7579099550dc, 0xda4019310680c182, 0x2ef48bba4f29e10b, 0x912fe7f2403c7055,
   0xf34488ff84ec3372, 0x4c9fe4b78bf9a22c, 0xb82b763cc25082a5, 0x07f01a74cd4513fb,
   0x7cfda8274bf004eb, 0xc326c46f44e595b5, 0x379256e40d4cb53c, 0x88493aac02592462,
   0xea2255a1c6896745, 0x55f939e9c99cf61b, 0xa14dab628035d692, 0x1e96c72a8f2047cc,
   0x5756cfc58d5ff8b2, 0xe88da38d824a69ec, 0x1c393106cbe34965, 0xa3e25d4ec4f6d83b,
   0xc189324300269b1c, 0x7e525e0b0f330a42, 0x8ae6cc80469a2acb, 0x353da0c8498fbb95,
   0x4e30129bcf3aac85, 0xf1eb7ed3c02f3ddb, 0x055fec5889861d52, 0xba84801086938c0c,
   0xd8efef1d4243cf2b, 0x673483554d565e75, 0x938011de04ff7efc, 0x2c5b7d960beaefa2,
   0xcb36eaf2132aa1b8, 0x74ed86ba1c3f30e6, 0x805914315596106f, 0x3f8278795a838131,
   0x5de917749e53c216, 0xe2327b3c91465348, 0x1686e9b7d8ef73c1, 0xa95d85ffd7fae29f,
   0xd25037ac514ff58f, 0x6d8b5be45e5a64d1, 0x993fc96f17f34458, 0x26e4a52718e6d506,
   0x448fca2adc369621, 0xfb54a662d323077f, 0x0fe034e99a8a27f6, 0xb03b58a1959fb6a8,
   0xf9fb504e97e009d6, 0x46203c0698f59888, 0xb294ae8dd15cb801, 0x0d4fc2c5de49295f,
   0x6f24adc81a996a78, 0xd0ffc180158cfb26, 0x244b530b5c25dbaf, 0x9b903f4353304af1,
   0xe09d8d10d5855de1, 0x5f46e158da90ccbf, 0xabf273d39339ec36, 0x14291f9b9c2c7d68,
   0x7642709658fc3e4f, 0xc9991cde57e9af11, 0x3d2d8e551e408f98, 0x82f6e21d11551ec6,
   0xaead9f8b1abff164, 0x1176f3c315aa603a, 0xe5c261485c0340b3, 0x5a190d005316d1ed,
   0x3872620d97c692ca, 0x87a90e4598d30394, 0x731d9cced17a231d, 0xccc6f086de6fb243,
   0xb7cb42d558daa553, 0x08102e9d57cf340d, 0xfca4bc161e661484, 0x437fd05e117385da,
   0x2114bf53d5a3c6fd, 0x9ecfd31bdab657a3, 0x6a7b4190931f772a, 0xd5a02dd89c0ae674,
   0x9c6025379e75590a, 0x23bb497f9160c854, 0xd70fdbf4d8c9e8dd, 0x68d4b7bcd7dc7983,
   0x0abfd8b1130c3aa4, 0xb564b4f91c19abfa, 0x41d0267255b08b73, 0xfe0b4a3a5aa51a2d,
   0x8506f869dc100d3d, 0x3add9421d3059c63, 0xce6906aa9aacbcea, 0x71b26ae295b92db4,
   0x13d905ef51696e93, 0xac0269a75e7cffcd, 0x58b6fb2c17d5df44, 0xe76d976418c04e1a,
   0xa2b4f3b77ec2d01b, 0x1d6f9fff71d74145, 0xe9db0d74387e61cc, 0x5600613c376bf092,
   0x346b0e31f3bbb3b5, 0x8bb06279fcae22eb, 0x7f04f0f2b5070262, 0xc0df9cbaba12933c,
   0xbbd22ee93ca7842c, 0x040942a133b21572, 0xf0bdd02a7a1b35fb, 0x4f66bc62750ea4a5,
   0x2d0dd36fb1dee782, 0x92d6bf27becb76dc, 0x66622dacf7625655, 0xd9b941e4f877c70b,
   0x9079490bfa087875, 0x2fa22543f51de92b, 0xdb16b7c8bcb4c9a2, 0x64cddb80b3a158fc,
   0x06a6b48d77711bdb, 0xb97dd8c578648a85, 0x4dc94a4e31cdaa0c, 0xf21226063ed83b52,
   0x891f9455b86d2c42, 0x36c4f81db778bd1c, 0xc2706a96fed19d95, 0x7dab06def1c40ccb,
   0x1fc069d335144fec, 0xa01b059b3a01deb2, 0x54af971073a8fe3b, 0xeb74fb587cbd6f65,
   0xc72f86ce775780c7, 0x78f4ea8678421199, 0x8c40780d31eb3110, 0x339b14453efea04e,
   0x51f07b48fa2ee369, 0xee2b1700f53b7237, 0x1a9f858bbc9252be, 0xa544e9c3b387c3e0,
   0xde495b903532d4f0, 0x619237d83a2745ae, 0x9526a553738e6527, 0x2afdc91b7c9bf479,
   0x4896a616b84bb75e, 0xf74dca5eb75e2600, 0x03f958d5fef70689, 0xbc22349df1e297d7,
   0xf5e23c72f39d28a9, 0x4a39503afc88b9f7, 0xbe8dc2b1b521997e, 0x0156aef9ba340820,
   0x633dc1f47ee44b07, 0xdce6adbc71f1da59, 0x28523f373858fad0, 0x9789537f374d6b8e,
   0xec84e12cb1f87c9e, 0x535f8d64beededc0, 0xa7eb1feff744cd49, 0x183073a7f8515c17,
   0x7a5b1caa3c811f30, 0xc58070e233948e6e, 0x3134e2697a3daee7, 0x8eef8e2175283fb9,
   0x698219456de871a3, 0xd659750d62fde0fd, 0x22ede7862b54c074, 0x9d368bce2441512a,
   0xff5de4c3e091120d, 0x4086888bef848353, 0xb4321a00a62da3da, 0x0be97648a9383284,
   0x70e4c41b2f8d2594, 0xcf3fa8532098b4ca, 0x3b8b3ad869319443, 0x845056906624051d,
   0xe63b399da2f4463a, 0x59e055d5ade1d764, 0xad54c75ee448f7ed, 0x128fab16eb5d66b3,
   0x5b4fa3f9e922d9cd, 0xe494cfb1e6374893, 0x10205d3aaf9e681a, 0xaffb3172a08bf944,
   0xcd905e7f645bba63, 0x724b32376b4e2b3d, 0x86ffa0bc22e70bb4, 0x3924ccf42df29aea,
   0x42297ea7ab478dfa, 0xfdf212efa4521ca4, 0x09468064edfb3c2d, 0xb69dec2ce2eead73,
   0xd4f68321263eee54, 0x6b2def69292b7f0a, 0x9f997de260825f83, 0x204211aa6f97cedd,
   0x0c196c3c647d217f, 0xb3c200746b68b021, 0x477692ff22c190a8, 0xf8adfeb72dd401f6,
   0x9ac691bae90442d1, 0x251dfdf2e611d38f, 0xd1a96f79afb8f306, 0x6e720331a0ad6258,
   0x157fb16226187548, 0xaaa4dd2a290de416, 0x5e104fa160a4c49f, 0xe1cb23e96fb155c1,
   0x83a04ce4ab6116e6, 0x3c7b20aca47487b8, 0xc8cfb227eddda731, 0x7714de6fe2c8366f,
   0x3ed4d680e0b78911, 0x810fbac8efa2184f, 0x75bb2843a60b38c6, 0xca60440ba91ea998,
   0xa80b2b066dceeabf, 0x17d0474e62db7be1, 0xe364d5c52b725b68, 0x5cbfb98d2467ca36,
   0x27b20bdea2d2dd26, 0x98696796adc74c78, 0x6cddf51de46e6cf1, 0xd3069955eb7bfdaf,
   0xb16df6582fabbe88, 0x0eb69a1020be2fd6, 0xfa02089b69170f5f, 0x45d964d366029e01,

   0x0000000000000000, 0x3ea616bd2ae10d77, 0x7d4c2d7a55c21aee, 0x43ea3bc77f231799,
   0xfa985af4ab8435dc, 0xc43e4c49816538ab, 0x87d4778efe462f32, 0xb9726133d4a72245,
   0xc1e993ba0f9ff8d3, 0xff4f8507257ef5a4, 0xbca5bec05a5de23d, 0x8203a87d70bcef4a,
   0x3b71c94ea41bcd0f, 0x05d7dff38efac078, 0x463de434f1d9d7e1, 0x789bf289db38da96,
   0xb70a012747a862cd, 0x89ac179a6d496fba, 0xca462c5d126a7823, 0xf4e03ae0388b7554,
   0x4d925bd3ec2c5711, 0x73344d6ec6cd5a66, 0x30de76a9b9ee4dff, 0x0e786014930f4088,
   0x76e3929d48379a1e, 0x4845842062d69769, 0x0bafbfe71df580f0, 0x3509a95a37148d87,
   0x8c7bc869e3b3afc2, 0xb2ddded4c952a2b5, 0xf137e513b671b52c, 0xcf91f3ae9c90b85b,
   0x5acd241dd7c756f1, 0x646b32a0fd265b86, 0x2781096782054c1f, 0x19271fdaa8e44168,
   0xa0557ee97c43632d, 0x9ef3685456a26e5a, 0xdd195393298179c3, 0xe3bf452e036074b4,
   0x9b24b7a7d858ae22, 0xa582a11af2b9a355, 0xe6689add8d9ab4cc, 0xd8ce8c60a77bb9bb,
   0x61bced5373dc9bfe, 0x5f1afbee593d9689, 0x1cf0c029261e8110, 0x2256d6940cff8c67,
   0xedc7253a906f343c, 0xd3613387ba8e394b, 0x908b0840c5ad2ed2, 0xae2d1efdef4c23a5,
   0x175f7fce3beb01e0, 0x29f96973110a0c97, 0x6a1352b46e291b0e, 0x54b5440944c81679,
   0x2c2eb6809ff0ccef, 0x1288a03db511c198, 0x51629bfaca32d601, 0x6fc48d47e0d3db76,
   0xd6b6ec743474f933, 0xe810fac91e95f444, 0xabfac10e61b6e3dd, 0x955cd7b34b57eeaa,
   0xb59a483baf8eade2, 0x8b3c5e86856fa095, 0xc8d66541fa4cb70c, 0xf67073fcd0adba7b,
   0x4f0212cf040a983e, 0x71a404722eeb9549, 0x324e3fb551c882d0, 0x0ce829087b298fa7,
   0x7473db81a0115531, 0x4ad5cd3c8af05846, 0x093ff6fbf5d34fdf, 0x3799e046df3242a8,
   0x8eeb81750b9560ed, 0xb04d97c821746d9a, 0xf3a7ac0f5e577a03, 0xcd01bab274b67774,
   0x0290491ce826cf2f, 0x3c365fa1c2c7c258, 0x7fdc6466bde4d5c1, 0x417a72db9705d8b6,
   0xf80813e843a2faf3, 0xc6ae05556943f784, 0x85443e921660e01d, 0xbbe2282f3c81ed6a,
   0xc379daa6e7b937fc, 0xfddfcc1bcd583a8b, 0xbe35f7dcb27b2d12, 0x8093e161989a2065,
   0x39e180524c3d0220, 0x074796ef66dc0f57, 0x44adad2819ff18ce, 0x7a0bbb95331e15b9,
   0xef576c267849fb13, 0xd1f17a9b52a8f664, 0x921b415c2d8be1fd, 0xacbd57e1076aec8a,
   0x15cf36d2d3cdcecf, 0x2b69206ff92cc3b8, 0x68831ba8860fd421, 0x56250d15aceed956,
   0x2ebeff9c77d603c0, 0x1018e9215d370eb7, 0x53f2d2e62214192e, 0x6d54c45b08f51459,
   0xd426a568dc52361c, 0xea80b3d5f6b33b6b, 0xa96a881289902cf2, 0x97cc9eafa3712185,
   0x585d6d013fe199de, 0x66fb7bbc150094a9, 0x2511407b6a238330, 0x1bb756c640c28e47,
   0xa2c537f59465ac02, 0x9c632148be84a175, 0xdf891a8fc1a7b6ec, 0xe12f0c32eb46bb9b,
   0x99b4febb307e610d, 0xa712e8061a9f6c7a, 0xe4f8d3c165bc7be3, 0xda5ec57c4f5d7694,
   0x632ca44f9bfa54d1, 0x5d8ab2f2b11b59a6, 0x1e608935ce384e3f, 0x20c69f88e4d94348,
   0x5fedb624078ac8af, 0x614ba0992d6bc5d8, 0x22a19b5e5248d241, 0x1c078de378a9df36,
   0xa575ecd0ac0efd73, 0x9bd3fa6d86eff004, 0xd839c1aaf9cce79d, 0xe69fd717d32deaea,
   0x9e04259e0815307c, 0xa0a2332322f43d0b, 0xe34808e45dd72a92, 0xddee1e59773627e5,
   0x649c7f6aa39105a0, 0x5a3a69d7897008d7, 0x19d05210f6531f4e, 0x277644addcb21239,
   0xe8e7b7034022aa62, 0xd641a1be6ac3a715, 0x95ab9a7915e0b08c, 0xab0d8cc43f01bdfb,
   0x127fedf7eba69fbe, 0x2cd9fb4ac14792c9, 0x6f33c08dbe648550, 0x5195d63094858827,
   0x290e24b94fbd52b1, 0x17a83204655c5fc6, 0x544209c31a7f485f, 0x6ae41f7e309e4528,
   0xd3967e4de439676d, 0xed3068f0ced86a1a, 0xaeda5337b1fb7d83, 0x907c458a9b1a70f4,
   0x05209239d04d9e5e, 0x3b868484faac9329, 0x786cbf43858f84b0, 0x46caa9feaf6e89c7,
   0xffb8c8cd7bc9ab82, 0xc11ede705128a6f5, 0x82f4e5b72e0bb16c, 0xbc52f30a04eabc1b,
   0xc4c90183dfd2668d, 0xfa6f173ef5336bfa, 0xb9852cf98a107c63, 0x87233a44a0f17114,
   0x3e515b7774565351, 0x00f74dca5eb75e26, 0x431d760d219449bf, 0x7dbb60b00b7544c8,
   0xb22a931e97e5fc93, 0x8c8c85a3bd04f1e4, 0xcf66be64c227e67d, 0xf1c0a8d9e8c6eb0a,
   0x48b2c9ea3c61c94f, 0x7614df571680c438, 0x35fee49069a3d3a1, 0x0b58f22d4342ded6,
   0x73c300a4987a0440, 0x4d651619b29b0937, 0x0e8f2ddecdb81eae, 0x30293b63e75913d9,
   0x895b5a5033fe319c, 0xb7fd4ced191f3ceb, 0xf417772a663c2b72, 0xcab161974cdd2605,
   0xea77fe1fa804654d, 0xd4d1e8a282e5683a, 0x973bd365fdc67fa3, 0xa99dc5d8d72772d4,
   0x10efa4eb03805091, 0x2e49b25629615de6, 0x6da3899156424a7f, 0x53059f2c7ca34708,
   0x2b9e6da5a79b9d9e, 0x15387b188d7a90e9, 0x56d240dff2598770, 0x68745662d8b88a07,
   0xd10637510c1fa842, 0xefa021ec26fea535, 0xac4a1a2b59ddb2ac, 0x92ec0c96733cbfdb,
   0x5d7dff38efac0780, 0x63dbe985c54d0af7, 0x2031d242ba6e1d6e, 0x1e97c4ff908f1019,
   0xa7e5a5cc4428325c, 0x9943b3716ec93f2b, 0xdaa988b611ea28b2, 0xe40f9e0b3b0b25c5,
   0x9c946c82e033ff53, 0xa2327a3fcad2f224, 0xe1d841f8b5f1e5bd, 0xdf7e57459f10e8ca,
   0x660c36764bb7ca8f, 0x58aa20cb6156c7f8, 0x1b401b0c1e75d061, 0x25e60db13494dd16,
   0xb0bada027fc333bc, 0x8e1cccbf55223ecb, 0xcdf6f7782a012952, 0xf350e1c500e02425,
   0x4a2280f6d4470660, 0x7484964bfea60b17, 0x376ead8c81851c8e, 0x09c8bb31ab6411f9,
   0x715349b8705ccb6f, 0x4ff55f055abdc618, 0x0c1f64c2259ed181, 0x32b9727f0f7fdcf6,
   0x8bcb134cdbd8feb3, 0xb56d05f1f139f3c4, 0xf6873e368e1ae45d, 0xc821288ba4fbe92a,
   0x07b0db25386b5171, 0x3916cd98128a5c06, 0x7afcf65f6da94b9f, 0x445ae0e2474846e8,
   0xfd2881d193ef64ad, 0xc38e976cb90e69da, 0x8064acabc62d7e43, 0xbec2ba16eccc7334,
   0xc659489f37f4a9a2, 0xf8ff5e221d15a4d5, 0xbb1565e56236b34c, 0x85b3735848d7be3b,
   0x3cc1126b9c709c7e, 0x026704d6b6919109, 0x418d3f11c9b28690, 0x7f2b29ace3538be7,

   0x0000000000000000, 0x169489cc969951e5, 0x2d2913992d32a3ca, 0x3bbd9a55bbabf22f,
   0x5a5227325a654794, 0x4cc6aefeccfc1671, 0x777b34ab7757e45e, 0x61efbd67e1ceb5bb,
   0xb4a44e64b4ca8f28, 0xa230c7a82253decd, 0x998d5dfd99f82ce2, 0x8f19d4310f617d07,
   0xeef66956eeafc8bc, 0xf862e09a78369959, 0xc3df7acfc39d6b76, 0xd54bf30355043a93,
   0x5d91ba9a31028d3b, 0x4b053356a79bdcde, 0x70b8a9031c302ef1, 0x662c20cf8aa97f14,
   0x07c39da86b67caaf, 0x11571464fdfe9b4a, 0x2aea8e3146556965, 0x3c7e07fdd0cc3880,
   0xe935f4fe85c80213, 0xffa17d32135153f6, 0xc41ce767a8faa1d9, 0xd2886eab3e63f03c,
   0xb367d3ccdfad4587, 0xa5f35a0049341462, 0x9e4ec055f29fe64d, 0x88da49996406b7a8,
   0xbb23753462051a76, 0xadb7fcf8f49c4b93, 0x960a66ad4f37b9bc, 0x809eef61d9aee859,
   0xe171520638605de2, 0xf7e5dbcaaef90c07, 0xcc58419f1552fe28, 0xdaccc85383cbafcd,
   0x0f873b50d6cf955e, 0x1913b29c4056c4bb, 0x22ae28c9fbfd3694, 0x343aa1056d646771,
   0x55d51c628caad2ca, 0x434195ae1a33832f, 0x78fc0ffba1987100, 0x6e688637370120e5,
   0xe6b2cfae5307974d, 0xf0264662c59ec6a8, 0xcb9bdc377e353487, 0xdd0f55fbe8ac6562,
   0xbce0e89c0962d0d9, 0xaa7461509ffb813c, 0x91c9fb0524507313, 0x875d72c9b2c922f6,
   0x521681cae7cd1865, 0x4482080671544980, 0x7f3f9253caffbbaf, 0x69ab1b9f5c66ea4a,
   0x0844a6f8bda85ff1, 0x1ed02f342b310e14, 0x256db561909afc3b, 0x33f93cad0603adde,
   0x429fcc3b9c9da787, 0x540b45f70a04f662, 0x6fb6dfa2b1af044d, 0x7922566e273655a8,
   0x18cdeb09c6f8e013, 0x0e5962c55061b1f6, 0x35e4f890ebca43d9, 0x2370715c7d53123c,
   0xf63b825f285728af, 0xe0af0b93bece794a, 0xdb1291c605658b65, 0xcd86180a93fcda80,
   0xac69a56d72326f3b, 0xbafd2ca1e4ab3ede, 0x8140b6f45f00ccf1, 0x97d43f38c9999d14,
   0x1f0e76a1ad9f2abc, 0x099aff6d3b067b59, 0x3227653880ad8976, 0x24b3ecf41634d893,
   0x455c5193f7fa6d28, 0x53c8d85f61633ccd, 0x6875420adac8cee2, 0x7ee1cbc64c519f07,
   0xabaa38c51955a594, 0xbd3eb1098fccf471, 0x86832b5c3467065e, 0x9017a290a2fe57bb,
   0xf1f81ff74330e200, 0xe76c963bd5a9b3e5, 0xdcd10c6e6e0241ca, 0xca4585a2f89b102f,
   0xf9bcb90ffe98bdf1, 0xef2830c36801ec14, 0xd495aa96d3aa1e3b, 0xc201235a45334fde,
   0xa3ee9e3da4fdfa65, 0xb57a17f13264ab80, 0x8ec78da489cf59af, 0x985304681f56084a,
   0x4d18f76b4a5232d9, 0x5b8c7ea7dccb633c, 0x6031e4f267609113, 0x76a56d3ef1f9c0f6,
   0x174ad0591037754d, 0x01de599586ae24a8, 0x3a63c3c03d05d687, 0x2cf74a0cab9c8762,
   0xa42d0395cf9a30ca, 0xb2b98a595903612f, 0x8904100ce2a89300, 0x9f9099c07431c2e5,
   0xfe7f24a795ff775e, 0xe8ebad6b036626bb, 0xd356373eb8cdd494, 0xc5c2bef22e548571,
   0x10894df17b50bfe2, 0x061dc43dedc9ee07, 0x3da05e6856621c28, 0x2b34d7a4c0fb4dcd,
   0x4adb6ac32135f876, 0x5c4fe30fb7aca993, 0x67f2795a0c075bbc, 0x7166f0969a9e0a59,
   0x853f9877393b4f0e, 0x93ab11bbafa21eeb, 0xa8168bee1409ecc4, 0xbe8202228290bd21,
   0xdf6dbf45635e089a, 0xc9f93689f5c7597f, 0xf244acdc4e6cab50, 0xe4d02510d8f5fab5,
   0x319bd6138df1c026, 0x270f5fdf1b6891c3, 0x1cb2c58aa0c363ec, 0x0a264c46365a3209,
   0x6bc9f121d79487b2, 0x7d5d78ed410dd657, 0x46e0e2b8faa62478, 0x50746b746c3f759d,
   0xd8ae22ed0839c235, 0xce3aab219ea093d0, 0xf5873174250b61ff, 0xe313b8b8b392301a,
   0x82fc05df525c85a1, 0x94688c13c4c5d444, 0xafd516467f6e266b, 0xb9419f8ae9f7778e,
   0x6c0a6c89bcf34d1d, 0x7a9ee5452a6a1cf8, 0x41237f1091c1eed7, 0x57b7f6dc0758bf32,
   0x36584bbbe6960a89, 0x20ccc277700f5b6c, 0x1b715822cba4a943, 0x0de5d1ee5d3df8a6,
   0x3e1ced435b3e5578, 0x2888648fcda7049d, 0x1335feda760cf6b2, 0x05a17716e095a757,
   0x644eca71015b12ec, 0x72da43bd97c24309, 0x4967d9e82c69b126, 0x5ff35024baf0e0c3,
   0x8ab8a327eff4da50, 0x9c2c2aeb796d8bb5, 0xa791b0bec2c6799a, 0xb1053972545f287f,
   0xd0ea8415b5919dc4, 0xc67e0dd92308cc21, 0xfdc3978c98a33e0e, 0xeb571e400e3a6feb,
   0x638d57d96a3cd843, 0x7519de15fca589a6, 0x4ea44440470e7b89, 0x5830cd8cd1972a6c,
   0x39df70eb30599fd7, 0x2f4bf927a6c0ce32, 0x14f663721d6b3c1d, 0x0262eabe8bf26df8,
   0xd72919bddef6576b, 0xc1bd9071486f068e, 0xfa000a24f3c4f4a1, 0xec9483e8655da544,
   0x8d7b3e8f849310ff, 0x9befb743120a411a, 0xa0522d16a9a1b335, 0xb6c6a4da3f38e2d0,
   0xc7a0544ca5a6e889, 0xd134dd80333fb96c, 0xea8947d588944b43, 0xfc1dce191e0d1aa6,
   0x9df2737effc3af1d, 0x8b66fab2695afef8, 0xb0db60e7d2f10cd7, 0xa64fe92b44685d32,
   0x73041a28116c67a1, 0x659093e487f53644, 0x5e2d09b13c5ec46b, 0x48b9807daac7958e,
   0x29563d1a4b092035, 0x3fc2b4d6dd9071d0, 0x047f2e83663b83ff, 0x12eba74ff0a2d21a,
   0x9a31eed694a465b2, 0x8ca5671a023d3457, 0xb718fd4fb996c678, 0xa18c74832f0f979d,
   0xc063c9e4cec12226, 0xd6f74028585873c3, 0xed4ada7de3f381ec, 0xfbde53b1756ad009,
   0x2e95a0b2206eea9a, 0x3801297eb6f7bb7f, 0x03bcb32b0d5c4950, 0x15283ae79bc518b5,
   0x74c787807a0bad0e, 0x62530e4cec92fceb, 0x59ee941957390ec4, 0x4f7a1dd5c1a05f21,
   0x7c832178c7a3f2ff, 0x6a17a8b4513aa31a, 0x51aa32e1ea915135, 0x473ebb2d7c0800d0,
   0x26d1064a9dc6b56b, 0x30458f860b5fe48e, 0x0bf815d3b0f416a1, 0x1d6c9c1f266d4744,
   0xc8276f1c73697dd7, 0xdeb3e6d0e5f02c32, 0xe50e7c855e5bde1d, 0xf39af549c8c28ff8,
   0x9275482e290c3a43, 0x84e1c1e2bf956ba6, 0xbf5c5bb7043e9989, 0xa9c8d27b92a7c86c,
   0x21129be2f6a17fc4, 0x3786122e60382e21, 0x0c3b887bdb93dc0e, 0x1aaf01b74d0a8deb,
   0x7b40bcd0acc43850, 0x6dd4351c3a5d69b5, 0x5669af4981f69b9a, 0x40fd2685176fca7f,
   0x95b6d586426bf0ec, 0x83225c4ad4f2a109, 0xb89fc61f6f595326, 0xae0b4fd3f9c002c3,
   0xcfe4f2b4180eb778, 0xd9707b788e97e69d, 0xe2cde12d353c14b2, 0xf45968e1a3a54557,

   0x0000000000000000, 0x0aed36d1a3bb9d7f, 0x15da6da347773afe, 0x1f375b72e4cca781,
   0x2bb4db468eee75fc, 0x2159ed972d55e883, 0x3e6eb6e5c9994f02, 0x348380346a22d27d,
   0x5769b68d1ddcebf8, 0x5d84805cbe677687, 0x42b3db2e5aabd106, 0x485eedfff9104c79,
   0x7cdd6dcb93329e04, 0x76305b1a3089037b, 0x69070068d445a4fa, 0x63ea36b977fe3985,
   0xaed36d1a3bb9d7f0, 0xa43e5bcb98024a8f, 0xbb0900b97cceed0e, 0xb1e43668df757071,
   0x8567b65cb557a20c, 0x8f8a808d16ec3f73, 0x90bddbfff22098f2, 0x9a50ed2e519b058d,
   0xf9badb9726653c08, 0xf357ed4685dea177, 0xec60b634611206f6, 0xe68d80e5c2a99b89,
   0xd20e00d1a88b49f4, 0xd8e336000b30d48b, 0xc7d46d72effc730a, 0xcd395ba34c47ee75,
   0x697ffc672fe43c8b, 0x6392cab68c5fa1f4, 0x7ca591c468930675, 0x7648a715cb289b0a,
   0x42cb2721a10a4977, 0x482611f002b1d408, 0x57114a82e67d7389, 0x5dfc7c5345c6eef6,
   0x3e164aea3238d773, 0x34fb7c3b91834a0c, 0x2bcc2749754fed8d, 0x21211198d6f470f2,
   0x15a291acbcd6a28f, 0x1f4fa77d1f6d3ff0, 0x0078fc0ffba19871, 0x0a95cade581a050e,
   0xc7ac917d145deb7b, 0xcd41a7acb7e67604, 0xd276fcde532ad185, 0xd89bca0ff0914cfa,
   0xec184a3b9ab39e87, 0xe6f57cea390803f8, 0xf9c22798ddc4a479, 0xf32f11497e7f3906,
   0x90c527f009810083, 0x9a281121aa3a9dfc, 0x851f4a534ef63a7d, 0x8ff27c82ed4da702,
   0xbb71fcb6876f757f, 0xb19cca6724d4e800, 0xaeab9115c0184f81, 0xa446a7c463a3d2fe,
   0xd2fff8ce5fc87916, 0xd812ce1ffc73e469, 0xc725956d18bf43e8, 0xcdc8a3bcbb04de97,
   0xf94b2388d1260cea, 0xf3a61559729d9195, 0xec914e2b96513614, 0xe67c78fa35eaab6b,
   0x85964e43421492ee, 0x8f7b7892e1af0f91, 0x904c23e00563a810, 0x9aa11531a6d8356f,
   0xae229505ccfae712, 0xa4cfa3d46f417a6d, 0xbbf8f8a68b8dddec, 0xb115ce7728364093,
   0x7c2c95d46471aee6, 0x76c1a305c7ca3399, 0x69f6f87723069418, 0x631bcea680bd0967,
   0x57984e92ea9fdb1a, 0x5d75784349244665, 0x42422331ade8e1e4, 0x48af15e00e537c9b,
   0x2b45235979ad451e, 0x21a81588da16d861, 0x3e9f4efa3eda7fe0, 0x3472782b9d61e29f,
   0x00f1f81ff74330e2, 0x0a1ccece54f8ad9d, 0x152b95bcb0340a1c, 0x1fc6a36d138f9763,
   0xbb8004a9702c459d, 0xb16d3278d397d8e2, 0xae5a690a375b7f63, 0xa4b75fdb94e0e21c,
   0x9034dfeffec23061, 0x9ad9e93e5d79ad1e, 0x85eeb24cb9b50a9f, 0x8f03849d1a0e97e0,
   0xece9b2246df0ae65, 0xe60484f5ce4b331a, 0xf933df872a87949b, 0xf3dee956893c09e4,
   0xc75d6962e31edb99, 0xcdb05fb340a546e6, 0xd28704c1a469e167, 0xd86a321007d27c18,
   0x155369b34b95926d, 0x1fbe5f62e82e0f12, 0x008904100ce2a893, 0x0a6432c1af5935ec,
   0x3ee7b2f5c57be791, 0x340a842466c07aee, 0x2b3ddf56820cdd6f, 0x21d0e98721b74010,
   0x423adf3e56497995, 0x48d7e9eff5f2e4ea, 0x57e0b29d113e436b, 0x5d0d844cb285de14,
   0x698e0478d8a70c69, 0x636332a97b1c9116, 0x7c5469db9fd03697, 0x76b95f0a3c6babe8,
   0x9126d7cfe7076147, 0x9bcbe11e44bcfc38, 0x84fcba6ca0705bb9, 0x8e118cbd03cbc6c6,
   0xba920c8969e914bb, 0xb07f3a58ca5289c4, 0xaf48612a2e9e2e45, 0xa5a557fb8d25b33a,
   0xc64f6142fadb8abf, 0xcca25793596017c0, 0xd3950ce1bdacb041, 0xd9783a301e172d3e,
   0xedfbba047435ff43, 0xe7168cd5d78e623c, 0xf821d7a73342c5bd, 0xf2cce17690f958c2,
   0x3ff5bad5dcbeb6b7, 0x35188c047f052bc8, 0x2a2fd7769bc98c49, 0x20c2e1a738721136,
   0x144161935250c34b, 0x1eac5742f1eb5e34, 0x019b0c301527f9b5, 0x0b763ae1b69c64ca,
   0x689c0c58c1625d4f, 0x62713a8962d9c030, 0x7d4661fb861567b1, 0x77ab572a25aeface,
   0x4328d71e4f8c28b3, 0x49c5e1cfec37b5cc, 0x56f2babd08fb124d, 0x5c1f8c6cab408f32,
   0xf8592ba8c8e35dcc, 0xf2b41d796b58c0b3, 0xed83460b8f946732, 0xe76e70da2c2ffa4d,
   0xd3edf0ee460d2830, 0xd900c63fe5b6b54f, 0xc6379d4d017a12ce, 0xccdaab9ca2c18fb1,
   0xaf309d25d53fb634, 0xa5ddabf476842b4b, 0xbaeaf08692488cca, 0xb007c65731f311b5,
   0x848446635bd1c3c8, 0x8e6970b2f86a5eb7, 0x915e2bc01ca6f936, 0x9bb31d11bf1d6449,
   0x568a46b2f35a8a3c, 0x5c67706350e11743, 0x43502b11b42db0c2, 0x49bd1dc017962dbd,
   0x7d3e9df47db4ffc0, 0x77d3ab25de0f62bf, 0x68e4f0573ac3c53e, 0x6209c68699785841,
   0x01e3f03fee8661c4, 0x0b0ec6ee4d3dfcbb, 0x14399d9ca9f15b3a, 0x1ed4ab4d0a4ac645,
   0x2a572b7960681438, 0x20ba1da8c3d38947, 0x3f8d46da271f2ec6, 0x3560700b84a4b3b9,
   0x43d92f01b8cf1851, 0x493419d01b74852e, 0x560342a2ffb822af, 0x5cee74735c03bfd0,
   0x686df44736216dad, 0x6280c296959af0d2, 0x7db799e471565753, 0x775aaf35d2edca2c,
   0x14b0998ca513f3a9, 0x1e5daf5d06a86ed6, 0x016af42fe264c957, 0x0b87c2fe41df5428,
   0x3f0442ca2bfd8655, 0x35e9741b88461b2a, 0x2ade2f696c8abcab, 0x203319b8cf3121d4,
   0xed0a421b8376cfa1, 0xe7e774ca20cd52de, 0xf8d02fb8c401f55f, 0xf23d196967ba6820,
   0xc6be995d0d98ba5d, 0xcc53af8cae232722, 0xd364f4fe4aef80a3, 0xd989c22fe9541ddc,
   0xba63f4969eaa2459, 0xb08ec2473d11b926, 0xafb99935d9dd1ea7, 0xa554afe47a6683d8,
   0x91d72fd0104451a5, 0x9b3a1901b3ffccda, 0x840d427357336b5b, 0x8ee074a2f488f624,
   0x2aa6d366972b24da, 0x204be5b73490b9a5, 0x3f7cbec5d05c1e24, 0x3591881473e7835b,
   0x0112082019c55126, 0x0bff3ef1ba7ecc59, 0x14c865835eb26bd8, 0x1e255352fd09f6a7,
   0x7dcf65eb8af7cf22, 0x7722533a294c525d, 0x68150848cd80f5dc, 0x62f83e996e3b68a3,
   0x567bbead0419bade, 0x5c96887ca7a227a1, 0x43a1d30e436e8020, 0x494ce5dfe0d51d5f,
   0x8475be7cac92f32a, 0x8e9888ad0f296e55, 0x91afd3dfebe5c9d4, 0x9b42e50e485e54ab,
   0xafc1653a227c86d6, 0xa52c53eb81c71ba9, 0xba1b0899650bbc28, 0xb0f63e48c6b02157,
   0xd31c08f1b14e18d2, 0xd9f13e2012f585ad, 0xc6c66552f639222c, 0xcc2b53835582bf53,
   0xf8a8d3b73fa06d2e, 0xf245e5669c1bf051, 0xed72be1478d757d0, 0xe79f88c5db6ccaaf,

   0x0000000000000000, 0xb0bc2e589204f500, 0x55a17ae27c9e796b, 0xe51d54baee9a8c6b,
   0xab42f5c4f93cf2d6, 0x1bfedb9c6b3807d6, 0xfee38f2685a28bbd, 0x4e5fa17e17a67ebd,
   0x625ccddaaaee76c7, 0xd2e0e38238ea83c7, 0x37fdb738d6700fac, 0x874199604474faac,
   0xc91e381e53d28411, 0x79a21646c1d67111, 0x9cbf42fc2f4cfd7a, 0x2c036ca4bd48087a,
   0xc4b99bb555dced8e, 0x7405b5edc7d8188e, 0x9118e157294294e5, 0x21a4cf0fbb4661e5,
   0x6ffb6e71ace01f58, 0xdf4740293ee4ea58, 0x3a5a1493d07e6633, 0x8ae63acb427a9333,
   0xa6e5566fff329b49, 0x165978376d366e49, 0xf3442c8d83ace222, 0x43f802d511a81722,
   0x0da7a3ab060e699f, 0xbd1b8df3940a9c9f, 0x5806d9497a9010f4, 0xe8baf711e894e5f4,
   0xbdaa1139f32e4877, 0x0d163f61612abd77, 0xe80b6bdb8fb0311c, 0x58b745831db4c41c,
   0x16e8e4fd0a12baa1, 0xa654caa598164fa1, 0x43499e1f768cc3ca, 0xf3f5b047e48836ca,
   0xdff6dce359c03eb0, 0x6f4af2bbcbc4cbb0, 0x8a57a601255e47db, 0x3aeb8859b75ab2db,
   0x74b42927a0fccc66, 0xc408077f32f83966, 0x211553c5dc62b50d, 0x91a97d9d4e66400d,
   0x79138a8ca6f2a5f9, 0xc9afa4d434f650f9, 0x2cb2f06eda6cdc92, 0x9c0ede3648682992,
   0xd2517f485fce572f, 0x62ed5110cdcaa22f, 0x87f005aa23502e44, 0x374c2bf2b154db44,
   0x1b4f47560c1cd33e, 0xabf3690e9e18263e, 0x4eee3db47082aa55, 0xfe5213ece2865f55,
   0xb00db292f52021e8, 0x00b19cca6724d4e8, 0xe5acc87089be5883, 0x5510e6281bbaad83,
   0x4f8d0420becb0385, 0xff312a782ccff685, 0x1a2c7ec2c2557aee, 0xaa90509a50518fee,
   0xe4cff1e447f7f153, 0x5473dfbcd5f30453, 0xb16e8b063b698838, 0x01d2a55ea96d7d38,
   0x2dd1c9fa14257542, 0x9d6de7a286218042, 0x7870b31868bb0c29, 0xc8cc9d40fabff929,
   0x86933c3eed198794, 0x362f12667f1d7294, 0xd33246dc9187feff, 0x638e688403830bff,
   0x8b349f95eb17ee0b, 0x3b88b1cd79131b0b, 0xde95e57797899760, 0x6e29cb2f058d6260,
   0x20766a51122b1cdd, 0x90ca4409802fe9dd, 0x75d710b36eb565b6, 0xc56b3eebfcb190b6,
   0xe968524f41f998cc, 0x59d47c17d3fd6dcc, 0xbcc928ad3d67e1a7, 0x0c7506f5af6314a7,
   0x422aa78bb8c56a1a, 0xf29689d32ac19f1a, 0x178bdd69c45b1371, 0xa737f331565fe671,
   0xf22715194de54bf2, 0x429b3b41dfe1bef2, 0xa7866ffb317b3299, 0x173a41a3a37fc799,
   0x5965e0ddb4d9b924, 0xe9d9ce8526dd4c24, 0x0cc49a3fc847c04f, 0xbc78b4675a43354f,
   0x907bd8c3e70b3d35, 0x20c7f69b750fc835, 0xc5daa2219b95445e, 0x75668c790991b15e,
   0x3b392d071e37cfe3, 0x8b85035f8c333ae3, 0x6e9857e562a9b688, 0xde2479bdf0ad4388,
   0x369e8eac1839a67c, 0x8622a0f48a3d537c, 0x633ff44e64a7df17, 0xd383da16f6a32a17,
   0x9ddc7b68e10554aa, 0x2d6055307301a1aa, 0xc87d018a9d9b2dc1, 0x78c12fd20f9fd8c1,
   0x54c24376b2d7d0bb, 0xe47e6d2e20d325bb, 0x01633994ce49a9d0, 0xb1df17cc5c4d5cd0,
   0xff80b6b24beb226d, 0x4f3c98ead9efd76d, 0xaa21cc5037755b06, 0x1a9de208a571ae06,
   0x9f1a08417d96070a, 0x2fa62619ef92f20a, 0xcabb72a301087e61, 0x7a075cfb930c8b61,
   0x3458fd8584aaf5dc, 0x84e4d3dd16ae00dc, 0x61f98767f8348cb7, 0xd145a93f6a3079b7,
   0xfd46c59bd77871cd, 0x4dfaebc3457c84cd, 0xa8e7bf79abe608a6, 0x185b912139e2fda6,
   0x5604305f2e44831b, 0xe6b81e07bc40761b, 0x03a54abd52dafa70, 0xb31964e5c0de0f70,
   0x5ba393f4284aea84, 0xeb1fbdacba4e1f84, 0x0e02e91654d493ef, 0xbebec74ec6d066ef,
   0xf0e16630d1761852, 0x405d48684372ed52, 0xa5401cd2ade86139, 0x15fc328a3fec9439,
   0x39ff5e2e82a49c43, 0x8943707610a06943, 0x6c5e24ccfe3ae528, 0xdce20a946c3e1028,
   0x92bdabea7b986e95, 0x220185b2e99c9b95, 0xc71cd108070617fe, 0x77a0ff509502e2fe,
   0x22b019788eb84f7d, 0x920c37201cbcba7d, 0x7711639af2263616, 0xc7ad4dc26022c316,
   0x89f2ecbc7784bdab, 0x394ec2e4e58048ab, 0xdc53965e0b1ac4c0, 0x6cefb806991e31c0,
   0x40ecd4a2245639ba, 0xf050fafab652ccba, 0x154dae4058c840d1, 0xa5f18018caccb5d1,
   0xebae2166dd6acb6c, 0x5b120f3e4f6e3e6c, 0xbe0f5b84a1f4b207, 0x0eb375dc33f04707,
   0xe60982cddb64a2f3, 0x56b5ac95496057f3, 0xb3a8f82fa7fadb98, 0x0314d67735fe2e98,
   0x4d4b770922585025, 0xfdf75951b05ca525, 0x18ea0deb5ec6294e, 0xa85623b3ccc2dc4e,
   0x84554f17718ad434, 0x34e9614fe38e2134, 0xd1f435f50d14ad5f, 0x61481bad9f10585f,
   0x2f17bad388b626e2, 0x9fab948b1ab2d3e2, 0x7ab6c031f4285f89, 0xca0aee69662caa89,
   0xd0970c61c35d048f, 0x602b22395159f18f, 0x85367683bfc37de4, 0x358a58db2dc788e4,
   0x7bd5f9a53a61f659, 0xcb69d7fda8650359, 0x2e74834746ff8f32, 0x9ec8ad1fd4fb7a32,
   0xb2cbc1bb69b37248, 0x0277efe3fbb78748, 0xe76abb59152d0b23, 0x57d695018729fe23,
   0x1989347f908f809e, 0xa9351a27028b759e, 0x4c284e9dec11f9f5, 0xfc9460c57e150cf5,
   0x142e97d49681e901, 0xa492b98c04851c01, 0x418fed36ea1f906a, 0xf133c36e781b656a,
   0xbf6c62106fbd1bd7, 0x0fd04c48fdb9eed7, 0xeacd18f2132362bc, 0x5a7136aa812797bc,
   0x76725a0e3c6f9fc6, 0xc6ce7456ae6b6ac6, 0x23d320ec40f1e6ad, 0x936f0eb4d2f513ad,
   0xdd30afcac5536d10, 0x6d8c819257579810, 0x8891d528b9cd147b, 0x382dfb702bc9e17b,
   0x6d3d1d5830734cf8, 0xdd813300a277b9f8, 0x389c67ba4ced3593, 0x882049e2dee9c093,
   0xc67fe89cc94fbe2e, 0x76c3c6c45b4b4b2e, 0x93de927eb5d1c745, 0x2362bc2627d53245,
   0x0f61d0829a9d3a3f, 0xbfddfeda0899cf3f, 0x5ac0aa60e6034354, 0xea7c84387407b654,
   0xa423254663a1c8e9, 0x149f0b1ef1a53de9, 0xf1825fa41f3fb182, 0x413e71fc8d3b4482,
   0xa98486ed65afa176, 0x1938a8b5f7ab5476, 0xfc25fc0f1931d81d, 0x4c99d2578b352d1d,
   0x02c673299c9353a0, 0xb27a5d710e97a6a0, 0x576709cbe00d2acb, 0xe7db27937209dfcb,
   0xcbd84b37cf41d7b1, 0x7b64656f5d4522b1, 0x9e7931d5b3dfaeda, 0x2ec51f8d21db5bda,
   0x609abef3367d2567, 0xd02690aba479d067, 0x353bc4114ae35c0c, 0x8587ea49d8e7a90c,

  };

#define VERIFY       0  // if 1, verify and time the implementation
#define VERBOSE      1  // if 1, tell about about progress when testing performance
#define PRINT_TABLES 0  // if 1, generate CsCrcTables.cpp

#if VERIFY || PRINT_TABLES
# include <windows.h>         // for Sleep()
# include <stdio.h>
# include "xrand2.h"
#endif

#ifndef _M_IX86 
#ifndef __aarch64__
# include <mmintrin.h>
# include <xmmintrin.h>
#endif
#endif

/* --------------------------- Implementation of CRC --------------------------- */
/*                             ---------------------                             */

/*
    Implements fast CRC, ideas can be traced back to work of Richard Black ("Fast CRC32 in Software")
    and Florian Braun and Marcel Waldvogel. Fast incremental CRC updates for IP over ATM networks.
    In Proceeding of 2001 IEEE Workshop on High Performance Switching and Routing, May 2001. http://citeseer.ist.psu.edu/braun01fast.html

    This implementation is slightly different from Black's and closer to Braun's variant.

    The idea of using eight tables in parallel came from Mark Manasse
    Interleaving four streams came from Andrew Kadatch
    Taking those four streams from every fourth 8-byte chunk came from Bob Jenkins
    MMX assembly for x86 came from Andrew Kadatch

    The greatest (1.5x) improvement perf improvement for 64-bit CRC on 32-bit x32 platform came from MMX
    implementation; however, on AMD64 regular 64-bit arithmetics is faster with regular registers -- and there
    are plenty of them, -- so there is no need to use MMX on AMD64.
*/


#define CRC_TABSIZE      256             // range of x in m_u1[x] and m_u32[CRC_TABSIZE*n + x]
#define CRC_U32LEN       sizeof(UInt64)  // range of x in m_u32[CRC_TABSIZE*x + n]
#define CRC_TRUNCATE(x)  ((x) & (CRC_TABSIZE-1))
#define CRC_U32OFF       32              // m_u32[CRC_TABSIZE*n + x] shifts a byte to the CRC CRC_U32OFF-7+n from now
#define CRC_MULTLEN      64              // number of terms in CsCrc*Mult[]

#pragma warning (push)
#pragma warning (disable: 4296) // conditional expression is constant
#pragma warning (disable: 4293) // '>>' : shift count negative or too big, undefined behavior (this code will never execute)
#pragma warning (disable: 4307) // '*' : integral constant overflow (this code will never execute)

#pragma optimize ("t", on)

struct CsCrc64
{
    UInt64 *m_uX2N;  // used to concatenate CRCs
    UInt64 *m_u1;    // shift to the CRC value 1 byte from now
    UInt64 *m_u32;   // shift to the CRC value 32 bytes from now
    UInt64  m_uPoly; // polynomial to use
    UInt64  m_uComplement; // complement to use
    const char *m_sName;   // name of this CRC

    //
    // Returns (a * b) mod POLY.
    // "a" and "b" are represented in "reversed" order -- LSB is x**(XX-1) coefficient, MSB is x^0 coefficient.
    // "POLY" is represented in the same manner except for omitted x**XX coefficient
    //
    UInt64
    MulPoly (
        UInt64 a,
        UInt64 b
    )
    {
        UInt64 r;
        UInt64 msb = m_uComplement ^ (m_uComplement>>1);

        for (r = 0;  a != 0;  a <<= 1)
        {
            if (a & msb)
            {
                r ^= b;
                a ^= msb;
            }

            b = (b >> 1 ) ^ ((b & 1) ? m_uPoly : 0);
        }

        return (r);
    }

    //
    // Returns (x ** (8*uSize)) mod POLY
    //
    UInt64
    ComputeX_N (UInt64 uSize)
    {
        Size_t i;
        UInt64 r;
        UInt64 msb = m_uComplement ^ (m_uComplement>>1);

        r = msb;    // r = reverse(1)
        for (i = 0; uSize != 0; uSize >>= 1, i += 1)
        {
            if (uSize & 1)
                r = MulPoly (r, m_uX2N[i]);
        }

        return (r);
    }

    //
    // Allows to change initial CRC value
    //
    UInt64
    ConvertInitialCrc (
        UInt64 uNew,
        UInt64 uOld,
        UInt64 uCrc,
        Size_t uSize
    )
    {
        //
        // CRC (A, uSize, uCrc) = (uCrc * x**uSize + A * x**XX) mod POLY (let's forget about double NOTs of uCrc)
        //
        // we know uCrc(uOld) = (uOld * x**uSize + A * x**XX) mod POLY; we need to compute
        // uCrc(uNew) = (uNew * x**uSize + A * x**XX) mod POLY
        //
        // uCrc(uNew) = uCrc(Old) + (uNew - uOld) * x**uSize)
        //

        uNew ^= uOld;
        uOld  = ComputeX_N (uSize);
        uOld  = MulPoly (uOld, uNew);
        uCrc ^= uOld;

        return (uCrc);
    }


    void
    InitializeTables (
        void
        )
    {
        Size_t i, j;
        UInt64 k;
        UInt64 msb = m_uComplement ^ (m_uComplement>>1);

        //
        // fill the table of powers of two
        //
        m_uX2N[0] = msb >> 8;
        for (i = 1; i < CRC_MULTLEN; ++i)
            m_uX2N[i] = MulPoly (m_uX2N[i-1], m_uX2N[i-1]);

        //
        // fill the table for shifting the CRC by 1 byte
        //
        for (i = 0; i < CRC_TABSIZE; ++i)
        {
            k = (UInt64) i;
            for (j = 0; j < 8; ++j)
            {
                k = (k >> 1 ) ^ ((k & 1) ? m_uPoly : 0);
            }
            m_u1[i] = k;
        }

        //
        // fill the tables for shifting the CRC by 32 bytes
        //
        k = ComputeX_N(CRC_U32OFF-CRC_U32LEN+1);
        for (i = 0; i < CRC_TABSIZE; ++i)
        {
            m_u32[i] = MulPoly(i, k);
        }
        for (; i<CRC_TABSIZE*sizeof(UInt64); ++i)
        {
            m_u32[i] = (m_u32[i-CRC_TABSIZE] >> 8) ^ m_u1[ CRC_TRUNCATE( m_u32[i-CRC_TABSIZE] ) ];
        }
    }


    //
    // Given
    //      uFinalCrcA = ComputeCrc (A, uSizeA, uInitialCrcA)
    // and
    //      uFinalCrcB = ComputeCrc (B, uSizeB, uInitialCrcB),
    // compute CRC of concatenation of A and B
    //      uFinalCrcAB = ComputeCrc (AB, uSizeA + uSizeB, uInitialCrcAB)
    // without touching A and B
    //
    // NB: uSizeA and/or uSizeB may be 0s (this trick may be used to "recompute" CRC for another initial value)
    //
    UInt64
    Concatenate (
        UInt64 uInitialCrcAB,
        UInt64 uInitialCrcA,
        UInt64 uFinalCrcA,
        UInt64 uSizeA,
        UInt64 uInitialCrcB,
        UInt64 uFinalCrcB,
        UInt64 uSizeB
        )
    {
        UInt64 uX_nA, uX_nB, uFinalCrcAB;

        //
        // Crc (X, uSizeX, uInitialCrcX) = ~(((~uInitialCrcX) * x**uSizeX + X * x**XX) mod POLY)
        //

        //
        // first, convert CRC's to canonical values getting rid of double bitwise NOT around uCrc
        //
        uInitialCrcAB   = uInitialCrcAB ^ m_uComplement;
        uInitialCrcA    = uInitialCrcA ^ m_uComplement;
        uFinalCrcA      = uFinalCrcA ^ m_uComplement;
        uInitialCrcB    = uInitialCrcB ^ m_uComplement;
        uFinalCrcB      = uFinalCrcB ^ m_uComplement;

        //
        // convert uFinalCrcX into canonical form, so that
        //      uFinalCrcX = (X * x**XX) mod POLY
        //
        uX_nA = ComputeX_N (uSizeA);
        uFinalCrcA ^= MulPoly (uX_nA, uInitialCrcA);
        uX_nB = ComputeX_N (uSizeB);
        uFinalCrcB ^= MulPoly (uX_nB, uInitialCrcB);

        //
        // we know
        //      uFinalCrcA = (A * x**XX) mod POLY
        //      uFinalCrcB = (B * x**XX) mod POLY
        // and need to compute
        //      uFinalCrcAB = (AB * x**XX) mod POLY =
        //                  = ((A * x**uSizeB + B) * x**XX) mod POLY =
        //                  = (A * x**XX) * x**uSizeB + B * x**XX mod POLY =
        //                  = uFinalCrcB + (uFinalCrcA * x**uSizeB) mod POLY
        //

        uFinalCrcAB = uFinalCrcB ^ MulPoly (uFinalCrcA, uX_nB);

        //
        // Finally, adjust initial value; we have
        //      uFinalCrcAB = (AB * x**XX) mod POLY
        // but want to have
        //      uFinalCrcAB = (UInitialCrcAB * x**(uSizeA + uSizeB) + AB * x**XX) mod POLY
        //

        uFinalCrcAB ^= MulPoly (uInitialCrcAB, MulPoly (uX_nA, uX_nB));

        // convert back to double NOT
        uFinalCrcAB = uFinalCrcAB ^ m_uComplement;

        return (uFinalCrcAB);
    }


    //
    // Compute the CRC the old simple way
    UInt64
    ComputeOld(
        const void *pSrc,
        Size_t      uSize,
        UInt64      uCrc
    )
    {
        Size_t i;
        const UInt8 *pData = (UInt8 *)pSrc;
        uCrc ^= m_uComplement;
        for (i=0; i<uSize; ++i)
            uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE( uCrc ^ pData[i] ) ];
        return uCrc ^= m_uComplement;
    }


    //
    // Compute the CRC of pData, which is of length uSize, starting with a CRC of uCrc
    //
#define CRC_DO(line,y) line(0,y); line(1,y); line(2,y); line(3,y)
#define CRC_DECLARE(x,y) UInt64 uCrc##x = 0
#define CRC_DECLAREB(x,y) UInt64 b##x
#define CRC_FETCH(x,y) b##x  = *(UInt64 *)(pData+(y)+8*(x)) ^ uCrc##x
#define CRC_INIT(x,y)  uCrc##x  = m_u32[(y)*CRC_TABSIZE + CRC_TRUNCATE(b##x)]; b##x >>= 8
#define CRC_ITER(x,y)  uCrc##x ^= m_u32[(y)*CRC_TABSIZE + CRC_TRUNCATE(b##x)]; b##x >>= 8
#define CRC_LAST(x,y)  uCrc##x ^= m_u32[(y)*CRC_TABSIZE + CRC_TRUNCATE(b##x)]
#define CRC_FINI(x,y) \
  uCrc^= *(UInt64 *)(pData+8*(x)) ^ uCrc##x; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]; \
  uCrc = (uCrc>>8) ^ m_u1[ CRC_TRUNCATE(uCrc) ]

    UInt64
    Compute(
        const void *pSrc,
        Size_t      uSize,
        UInt64      uCrc
    )
    {
        const UInt8 *pData = (const UInt8 *)pSrc;
        Size_t uBytes, uStop;

        uCrc ^= m_uComplement;

        //
        // align data on UInt64 boundary
        //

        uStop = ((Size_t)(- (INT_PTR) pData)) & (sizeof (UInt64) - 1);
        if (uStop != 0)
        {
            if (uStop > uSize)
                uStop = uSize;
            for (uBytes = 0; uBytes < uStop; ++uBytes)
                uCrc = (uCrc >> 8) ^ m_u1[ CRC_TRUNCATE(uCrc ^ pData[uBytes]) ];
            uSize -= uStop;
            pData += uStop;
        }

        //
        // Compute the CRC for most of the array
        //
        // Use four independent accumulators, uCrc0..uCrc3
        // Each aligned 32-byte block is split into four 8-byte blocks, one block per accumulator
        // This is XORed with the current accumulator, then each byte is mapped to the CRC shifted 32 bytes ahead.
        // Mapping accumulators 32 bytes ahead is interleaved, which leaves time for the shifts to complete.
        // The handling of the final 32 bytes also accumulates the four accumulators.
        //
        uBytes=0;
        uStop = uSize - (uSize%CRC_U32OFF);
        if (uStop >= 2*CRC_U32OFF)
        {
            CRC_DO(CRC_DECLARE,0);     // declare uCrc0..3
            const UInt8 *pLast = pData + uStop - CRC_U32OFF;
            uSize -= uStop;
            uCrc0 = uCrc;

            //
            // Loop over all 32 byte chunks except the last one.
            // Split 32 bytes into four 8-byte chunks, XOR them to b0..b3.
            // Then map b0..b3 32 bytes ahead into uCrc0..uCrc3.
            // Interleave the mapping work to give the shifts enough time to complete.
            //

#if defined (_M_IX86)
            //
            // use MMX for 32 bit x86
            // duplicate the code for CRC32 and CRC64 so the assembly can constant-fold the table addresses
            //
            if (m_uComplement == (UInt64)0xffffffff)
            {
                __asm
                {
                    mov     edi, pData

                    movq    mm0, uCrc0
                    movq    mm1, uCrc1
                    movq    mm2, uCrc2
                    movq    mm3, uCrc3

                    NextIteration:
                    movq    mm4, [edi]          // mm4    = ((UInt64 *)pData)[0]
                    pxor    mm4, mm0            // uCrc0 ^= ((UInt64 *)pData)[0]
                    movd    eax, mm4            // eax    = uCrc0.lo
                    psrlq   mm4, 32

                    movq    mm5, [edi + 8]      // mm5    = ((UInt64 *)pData)[1]
                    pxor    mm5, mm1            // uCrc1 ^= ((UInt64 *)pData)[1]
                    movd    ebx, mm5            // ebx    = uCrc1.lo
                    psrlq   mm5, 32

                    movq    mm6, [edi + 16]     // mm6    = ((UInt64 *)pData)[2]
                    pxor    mm6, mm2            // uCrc2 ^= ((UInt64 *)pData)[2]
                    movd    ecx, mm6            // ecx    = uCrc2.lo
                    psrlq   mm6, 32

                    movq    mm7, [edi + 24]     // mm7    = ((UInt64 *)pData)[3]
                    pxor    mm7, mm3            // uCrc3 ^= ((UInt64 *)pData)[3]
                    movd    edx, mm7            // edx    = uCrc3.lo
                    psrlq   mm7, 32

                    movzx   esi, al
                    shr     eax, 8
                    movq    mm0, CsCrc32Map32[7 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    movq    mm1, CsCrc32Map32[7 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    movq    mm2, CsCrc32Map32[7 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    movq    mm3, CsCrc32Map32[7 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc32Map32[6 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc32Map32[6 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc32Map32[6 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc32Map32[6 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc32Map32[5 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc32Map32[5 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc32Map32[5 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc32Map32[5 * 256 * 8 + esi*8]

                    pxor    mm0, CsCrc32Map32[4 * 256 * 8 + eax*8]
                    movd    eax, mm4
                    pxor    mm1, CsCrc32Map32[4 * 256 * 8 + ebx*8]
                    movd    ebx, mm5
                    pxor    mm2, CsCrc32Map32[4 * 256 * 8 + ecx*8]
                    movd    ecx, mm6
                    pxor    mm3, CsCrc32Map32[4 * 256 * 8 + edx*8]
                    movd    edx, mm7

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc32Map32[3 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc32Map32[3 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc32Map32[3 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc32Map32[3 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc32Map32[2 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc32Map32[2 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc32Map32[2 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc32Map32[2 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc32Map32[1 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc32Map32[1 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc32Map32[1 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc32Map32[1 * 256 * 8 + esi*8]

                    add     edi, 32             // pData += 32

                    pxor    mm0, CsCrc32Map32[eax*8]
                    pxor    mm1, CsCrc32Map32[ebx*8]
                    pxor    mm2, CsCrc32Map32[ecx*8]
                    pxor    mm3, CsCrc32Map32[edx*8]

                    cmp     edi, pLast          // while (pData < pLast)
                    jb      NextIteration

                    movq    uCrc0, mm0          // get CRC
                    movq    uCrc1, mm1
                    movq    uCrc2, mm2
                    movq    uCrc3, mm3
                    mov     pData, edi
                    emms                        // stop using MMX
                }
            }
            else
            {
                __asm
                {
                    mov     edi, pData

                    movq    mm0, uCrc0
                    movq    mm1, uCrc1
                    movq    mm2, uCrc2
                    movq    mm3, uCrc3

                    NextIteration2:
                    movq    mm4, [edi]          // mm4    = ((UInt64 *)pData)[0]
                    pxor    mm4, mm0            // uCrc0 ^= ((UInt64 *)pData)[0]
                    movd    eax, mm4            // eax    = uCrc0.lo
                    psrlq   mm4, 32

                    movq    mm5, [edi + 8]      // mm5    = ((UInt64 *)pData)[1]
                    pxor    mm5, mm1            // uCrc1 ^= ((UInt64 *)pData)[1]
                    movd    ebx, mm5            // ebx    = uCrc1.lo
                    psrlq   mm5, 32

                    movq    mm6, [edi + 16]     // mm6    = ((UInt64 *)pData)[2]
                    pxor    mm6, mm2            // uCrc2 ^= ((UInt64 *)pData)[2]
                    movd    ecx, mm6            // ecx    = uCrc2.lo
                    psrlq   mm6, 32

                    movq    mm7, [edi + 24]     // mm7    = ((UInt64 *)pData)[3]
                    pxor    mm7, mm3            // uCrc3 ^= ((UInt64 *)pData)[3]
                    movd    edx, mm7            // edx    = uCrc3.lo
                    psrlq   mm7, 32

                    movzx   esi, al
                    shr     eax, 8
                    movq    mm0, CsCrc64Map32[7 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    movq    mm1, CsCrc64Map32[7 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    movq    mm2, CsCrc64Map32[7 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    movq    mm3, CsCrc64Map32[7 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc64Map32[6 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc64Map32[6 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc64Map32[6 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc64Map32[6 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc64Map32[5 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc64Map32[5 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc64Map32[5 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc64Map32[5 * 256 * 8 + esi*8]

                    pxor    mm0, CsCrc64Map32[4 * 256 * 8 + eax*8]
                    movd    eax, mm4
                    pxor    mm1, CsCrc64Map32[4 * 256 * 8 + ebx*8]
                    movd    ebx, mm5
                    pxor    mm2, CsCrc64Map32[4 * 256 * 8 + ecx*8]
                    movd    ecx, mm6
                    pxor    mm3, CsCrc64Map32[4 * 256 * 8 + edx*8]
                    movd    edx, mm7

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc64Map32[3 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc64Map32[3 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc64Map32[3 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc64Map32[3 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc64Map32[2 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc64Map32[2 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc64Map32[2 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc64Map32[2 * 256 * 8 + esi*8]

                    movzx   esi, al
                    shr     eax, 8
                    pxor    mm0, CsCrc64Map32[1 * 256 * 8 + esi*8]
                    movzx   esi, bl
                    shr     ebx, 8
                    pxor    mm1, CsCrc64Map32[1 * 256 * 8 + esi*8]
                    movzx   esi, cl
                    shr     ecx, 8
                    pxor    mm2, CsCrc64Map32[1 * 256 * 8 + esi*8]
                    movzx   esi, dl
                    shr     edx, 8
                    pxor    mm3, CsCrc64Map32[1 * 256 * 8 + esi*8]

                    add     edi, 32             // pData += 32

                    pxor    mm0, CsCrc64Map32[eax*8]
                    pxor    mm1, CsCrc64Map32[ebx*8]
                    pxor    mm2, CsCrc64Map32[ecx*8]
                    pxor    mm3, CsCrc64Map32[edx*8]

                    cmp     edi, pLast          // while (pData < pLast)
                    jb      NextIteration2

                    movq    uCrc0, mm0          // get CRC
                    movq    uCrc1, mm1
                    movq    uCrc2, mm2
                    movq    uCrc3, mm3
                    mov     pData, edi
                    emms                        // stop using MMX
                }
            }
#else /* AMD64 and ARM64 */
            for ( ;  pData < pLast;  pData += CRC_U32OFF)
            {
                CRC_DO( CRC_DECLAREB,0);
#if __aarch64__
                __builtin_prefetch((const char *)pData+256);
#else
                _mm_prefetch((const char *)pData+256, _MM_HINT_T1);
#endif

                CRC_DO( CRC_FETCH, 0);
                CRC_DO( CRC_INIT, 7);
                CRC_DO( CRC_ITER, 6);
                CRC_DO( CRC_ITER, 5);
                CRC_DO( CRC_ITER, 4);
                CRC_DO( CRC_ITER, 3);
                CRC_DO( CRC_ITER, 2);
                CRC_DO( CRC_ITER, 1);
                CRC_DO( CRC_LAST, 0);
            }
#endif

            //
            // Handle the last complete 32-byte chunk, and accumulate uCrc0..uCrc3 back into uCrc.
            //
            uCrc = 0;
            CRC_DO(CRC_FINI,0);
            pData += CRC_U32OFF;
        }             // if (uStop >= 2*CRC_U32OFF)

        //
        // handle the tail
        //
        for (uBytes = 0;  uBytes < uSize;  ++uBytes)
            uCrc =  (uCrc >> 8) ^ m_u1[ CRC_TRUNCATE( uCrc ^ pData[ uBytes ] ) ];

        return (uCrc ^ m_uComplement);
    }

#undef CRC_FINI
#undef CRC_LAST
#undef CRC_ITER
#undef CRC_INIT
#undef CRC_FETCH
#undef CRC_DECLAREB
#undef CRC_DECLARE
#undef CRC_DO


    //
    // Do some random computation over all the "constant" values in this class, looking for memory corruptions
    //
    UInt64
    CheckTables (
        void
    )
    {
        UInt64 uCrc = m_uComplement ^ m_uPoly;
        UInt64 a = Compute(m_uX2N, CRC_MULTLEN*sizeof(UInt64), uCrc);
        UInt64 b = Compute(m_u1, CRC_TABSIZE*sizeof(UInt64), uCrc);
        UInt64 c = Compute(m_u32, CRC_TABSIZE*sizeof(UInt64)*sizeof(UInt64), uCrc);
        return a ^ Concatenate ( 42, 2001, b, 13, 3, c, 99);
    }


#if PRINT_TABLES
    void
    PrintTables (
        void
    )
    {
        Size_t i, j;

        InitializeTables ();

        printf ("\n/* ---------------------------------- Tables for %s ----------------------------------- */\n", m_sName);
        printf (  "/*                                    ");
        i = strlen (m_sName) + 11;
        do
        {
            printf ("-");
        }
        while (--i != 0);
        printf ("                                     */\n\n");

        printf ("//\n// Generating polynomial for %s is\n", m_sName);
        printf ("// 0x%0*I64x =\n//%*s      x^%u",
                sizeof (UInt64) * 2, m_uPoly, (int) sizeof (UInt64) * 2, "", sizeof (UInt64) * 8);
        i = 8 * sizeof (UInt64);
        j = 0;
        do
        {
            --i;
            if (m_uPoly & (((UInt64) 1) << (8 * sizeof (UInt64) - 1 - i)))
            {
                if (j != 0 && j % 10 == 0)
                    printf (" + \n//%*s          ", (int) sizeof (UInt64) * 2, "");
                printf (" + x^%-2Iu", i);
                ++j;
            }
        }
        while (i != 0);
        printf ("\n//\n\n");

        printf ("UInt64\nCs%sMult[%d] =\n{\n  ", m_sName, CRC_MULTLEN);
        for (i = 0; i < CRC_MULTLEN; ++i)
        {
            printf (" 0x%0*I64x,", 16, m_uX2N[i]);
            if ((i & 3) == 3)
                printf("\n  ");
        }
        printf ("};\n\n");

        printf ("static UInt64 Cs%sMap1[%d] =\n{\n  ", m_sName, CRC_TABSIZE);
        for (i = 0; i < 256; ++i)
        {
            printf (" 0x%0*I64x,", 16, m_u1[i]);
            if ((i & 3) == 3)
                printf("\n  ");
        }
        printf ("};\n\n");

        printf ("static UInt64 Cs%sMap32[%d] =\n{\n  ", m_sName, CRC_U32LEN*CRC_TABSIZE);
        for (j=0; j<CRC_U32LEN; ++j)
        {
            for (i = 0; i < 256; ++i)
            {
                printf (" 0x%0*I64x,", 16, m_u32[j*CRC_TABSIZE + i]);
                if ((i & 3) == 3)
                printf("\n  ");
            }
            printf ("\n  ");
        }
        printf ("};\n\n");
    }
#endif   // PRINT_TABLES
};  // end of struct CsCrc64



/* ---------------------- 32 and 64 bit CRC with specific generating polynomials ---------------------- */
/*                        ------------------------------------------------------                        */

/*
  see: David Jones, "An Improved 64-bit Cyclic Redundancy Check for Protein Sequences"

  "Traditional" primitive polynom (SWISS-POLY),
        x64 + x4 + x3 + x + 1,
  (as any other primitive polynomial in GF(2^64)) is good for detection for up to 64 _consecutive_ bit errors,
  but may miss many 2-4 bit corruptions spread over large block of data. Jones (2002) suggests using much more dense
  polynomial,
        x64 + x63 + x61 + x59 + x58 + x56 + x55 + x52 + x49 + x48 + x47 +
        x46 + x44 + x41 + x37 + x36 + x34 + x32 + x31 + x28 + x26 + x23 +
        x22 + x19 + x16 + x13 + x12 + x10 + x9 + x6 + x4 + x3 + 1,
  to overcome this problem.

  See also http://www.ecma-international.org/publications/standards/Ecma-182.htm (DTL1 format, 1992) which uses
        x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 +
        x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 +
        x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 +
        x^7 + x^4 + x + 1

  see also http://www.diskdrive.com/reading-room/white-papers/draft-sheinwald-iscsi-crc-01.pdf and
  http://www.rfc-archive.org/getrfc.php?rfc=3385
  for comparison of CRCs and checksums.

  CRC32C is (1)1EDC6F41 (d=4 at 2^32-1) inverted: 0x82f63b78, poly:
     x32+x28+x27+x26+x25+x23+x22+x20+x19+x18+x14+x13+x11+x10+x9+x8+x6+1

  CRC32Q is (1)814141AB
  IEEE-802 CRC is (1)04C11DB7 (d=4 at 2^16-1)
  CCITT-CRC32 is x^32+x^31+x^4+1

*/

static CsCrc64 Crc32 = { CsCrc32Mult, CsCrc32Map1, CsCrc32Map32, 0x82f63b78, (UInt64)(~(UInt32)0), "Crc32" };
static CsCrc64 Crc64 = { CsCrc64Mult, CsCrc64Map1, CsCrc64Map32, 0x9a6c9329ac4bc9b5, ~(UInt64)0, "Crc64" };

#pragma warning (pop)



/* ----------------------------------------------- 32 and 64 bit CRCs -------------------------------------------- */
/*                                                 ------------------                                              */


extern "C"
UInt32
CSCRCAPI
CsCrc32Compute (
    const void *pSrc,
    Size_t      uSize,
    UInt32      uCrc
)
{
    return (UInt32)Crc32.Compute ((const UInt8 *)pSrc, uSize, uCrc);
}

extern "C"
BOOL
CSCRCAPI
CsCrc32SelfTest()
{
    return (0xc2bfbb16 == (UInt32)Crc32.CheckTables());
}


extern "C"
UInt32
CSCRCAPI
CsCrc32Concatenate (
    UInt32 uInitialCrcAB,
    UInt32 uInitialCrcA,
    UInt32 uFinalCrcA,
    UInt64 uSizeA,
    UInt32 uInitialCrcB,
    UInt32 uFinalCrcB,
    UInt64 uSizeB
)
{
    return (UInt32)(
        Crc32.Concatenate (
            uInitialCrcAB,
            uInitialCrcA,
            uFinalCrcA,
            uSizeA,
            uInitialCrcB,
            uFinalCrcB,
            uSizeB
        )
    );
}



extern "C"
UInt64
CSCRCAPI
CsCrc64Compute (
    const void *pSrc,
    Size_t      uSize,
    UInt64      uCrc
)
{
    return Crc64.Compute ((const UInt8 *)pSrc, uSize, uCrc);
}

extern "C"
UInt64
CSCRCAPI
CsCrc64Concatenate (
    UInt64 uInitialCrcAB,
    UInt64 uInitialCrcA,
    UInt64 uFinalCrcA,
    UInt64 uSizeA,
    UInt64 uInitialCrcB,
    UInt64 uFinalCrcB,
    UInt64 uSizeB
)
{
    return (
        Crc64.Concatenate (
            uInitialCrcAB,
            uInitialCrcA,
            uFinalCrcA,
            uSizeA,
            uInitialCrcB,
            uFinalCrcB,
            uSizeB
        )
    );
}


extern "C"
BOOL
CSCRCAPI
CsCrc64SelfTest()
{
    return (0xc747de0d7f9944fe == Crc64.CheckTables());
}



#if PRINT_TABLES
int
__cdecl
main (
    void
)
{
    printf ("#ifndef _CSCRCTABLES_H_\n");
    printf ("#define _CSCRCTABLES_H_\n\n");
    printf ("#pragma once\n\n");
    Crc32.PrintTables();
    Crc64.PrintTables();
    printf ("\n#endif /* _CSCRCTABLES_H_ */\n\n");

    return (0);
}
#endif




#if VERIFY
int
__cdecl
main (
    void
)
{
    UInt8        *pData;
    xrand51_table xr;
    Size_t        i;

    pData = (UInt8 *) malloc (N + 1);
    if (pData == NULL)
    {
        printf ("cannot allocate %u bytes\n", N);
        return (1);
    }
    ++pData;

    xrand51_init (&xr, 0x12345);

    for (i = 0; i < N; i += sizeof (xrand_value))
    {
        * (xrand_value *) (pData + i) = xrand51 (&xr);
    }


    Crc64.Test (pData);

    Crc32.Test (pData);

    return (0);
}

#undef N
#undef N_TESTS

#endif

#if defined _WIN64

ULONG
KChecksumHardwareCrc32(
    __in_bcount(Size) const VOID* Buffer,
    __in ULONG Size,
    __in ULONG InitialCrc
    )
{
    ULONGLONG* p = (ULONGLONG*) Buffer;
    ULONGLONG crc = InitialCrc^0xFFFFFFFF;
    ULONG n;
    ULONG i;

    n = Size/sizeof(ULONGLONG);

#if !defined(PLATFORM_UNIX)  // FIXME: _mm_crc32_u64 replacement
    for (i = 0; i < n; i++) {
        crc = _mm_crc32_u64(crc, p[i]);
    }
#endif
    return (ULONG) (crc^0xFFFFFFFF);
}

#endif

ULONG
KChecksum::Crc32(
    __in_bcount(Size) const VOID* Source,
    __in ULONG Size,
    __in ULONG InitialCrc
    )

/*++

Routine Description:

    This routine computes the CRC32 of the given buffer according to the Catagnoli polynomial.

Arguments:

    Source      - Supplies the source buffer.

    Size        - Supplies the size of the source buffer, in bytes.

    InitialCrc  - Supplies the initial CRC, for computing a CRC incrementally.

Return Value:

    The CRC32 of the given buffer.

--*/

{
#if defined _WIN64 && !defined(PLATFORM_UNIX)

    ULONG crc = 0;

    if (!DisableHwCrcAssist && Size%sizeof(ULONGLONG) == 0 && ((ULONG_PTR) Source)%sizeof(ULONGLONG) == 0) {

        //
        // In the case where HW assist hasn't been disable, and the size and memory offset of the buffer are aligned
        // to an 8 byte boundary, use the HW acceleration.
        //

        _try {

            crc = KChecksumHardwareCrc32(Source, Size, InitialCrc);

        } _except (EXCEPTION_EXECUTE_HANDLER) {

            //
            // If we get here then this means that the instruction required for this is not available.
            // Disable the HW crc assist state so that we don't try it again.
            //

            InterlockedExchange(&DisableHwCrcAssist, TRUE);
        }

        if (!DisableHwCrcAssist) {

            //
            // If the HW assist is still enabled, then it must be that we computed the answer.
            //

            return crc;
        }
    }

#endif

    //
    // In all other cases just rely on the normal CRC32 computation without HW assist.
    //

    return CsCrc32Compute(Source, Size, InitialCrc);
}

ULONGLONG
KChecksum::Crc64(
    __in_bcount(Size) const VOID* Source,
    __in ULONG Size,
    __in ULONGLONG InitialCrc
    )

/*++

Routine Description:

    This routine computes the CRC64 of the given buffer.

Arguments:

    Source      - Supplies the source buffer.

    Size        - Supplies the size of the source buffer, in bytes.

    InitialCrc  - Supplies the initial CRC, for computing a CRC incrementally.

Return Value:

    The CRC64 of the given buffer.

--*/

{
    return CsCrc64Compute(Source, Size, InitialCrc);
}

ULONGLONG
KChecksum::Hash64(
    __in_bcount(Size) const VOID* Source,
    __in ULONG Size,
    __in ULONGLONG InitialHash
    )

/*++

Routine Description:

    This routine implements Dave Cutler's HASH64 algorithm.  This algorithm is 4x faster than CRC64 in some tests.  It is bound
    to be faster because it does not use large lookup tables.

Arguments:

    Source      - Supplies the source buffer.

    Size        - Supplies the size of the source buffer, in bytes, must be a multiple of 64.

    InitialHash - Supplies the initial hash, for computing a hash incrementally.  The first call when accumulating must
                    have the initial hash set to the product of the 2 large primes which is the default on this argument.

Return Value:

    The HASH64 of the given buffer.

--*/

{
    ULONGLONG* hashPage = (ULONGLONG*) Source;
    ULONGLONG hash = InitialHash;
    ULONG n = Size/sizeof(ULONGLONG);
    ULONG j;

    //
    // This assert is there to catch the error of starting with a 0.  In theory you could get 0 as an intermediary result
    // so this assert is checked only, to find bugs, since a valid 0 can happen in production.
    //

    KAssert(hash);

    //
    // The caller's input must be a multiple of 64 bytes.
    //

    KFatal(Size%64 == 0);

    for (j = 0; j < n; j += 8) {

        hash = RotateRight64 (hash, 2);
        hash += hashPage[j];
        hash = RotateRight64 (hash, 3);
        hash += hashPage[j + 1];
        hash = RotateRight64 (hash, 5);
        hash += hashPage[j + 2];
        hash = RotateRight64 (hash, 7);
        hash += hashPage[j + 3];
        hash = RotateRight64 (hash, 11);
        hash ^= hashPage[j + 4];
        hash = RotateRight64 (hash, 13);
        hash += hashPage[j + 5];
        hash = RotateRight64 (hash, 17);
        hash += hashPage[j + 6];
        hash = RotateRight64 (hash, 19);
        hash += hashPage[j + 7];

    }

    return hash;
}
